Rewrite query so the WHEN clause won't affect Right outer Join - sql

So, I just want to change the inner join to right outer join but it keeps inner joining everything. I've tried all kinds of join but the results for inner join keeps on showing
Or if anyone has any tips on how I can rewrite this query, joining 2 tables with their own WHERE clause filter without the WHERE clause messing up the JOIN. And I read somewhere that the WHERE clause affects the JOIN
DECLARE #BranchC VARCHAR(500) = '01001'
DECLARE #Range1 VARCHAR(255) = '202101'
DECLARE #Range2 VARCHAR(255) = '202201'
SELECT
sub1.*
FROM
(
SELECT
ISNULL(r1.ItemID, r2.ItemID) AS ItemID,
r2.TotalItemPrice as R2_ItemPrice,
r1.TotalItemPrice AS R1_ItemPrice
FROM
(
SELECT
ItemID,
SUM(TotalItemPrice) AS TotalItemPrice
FROM
DM.M
WHERE
0 = 0
AND InvoiceYearMonth IN (SELECT VALUE FROM dbo.SplitString(#Range1,','))
AND BranchCode IN (SELECT ITEM FROM dbo.DelimitedSplit8K(#BranchC,N','))
GROUP BY
ItemID
) r1
INNER JOIN -- wanted to make this as right outer join
(
SELECT
ItemID,
SUM(TotalItemPrice) AS TotalItemPrice
FROM
DM.M
WHERE
0 = 0
AND InvoiceYearMonth IN (SELECT VALUE FROM dbo.SplitString(#Range2,','))
AND BranchCode IN (SELECT ITEM FROM dbo.DelimitedSplit8K(#BranchC,N','))
GROUP BY
ItemID
) r2
ON r1.ItemID = r2.ItemID
WHERE
0 = 0
AND r1.ItemID NOT IN (SELECT ItemID FROM DM.C)
AND r2.ItemID NOT IN (SELECT ItemID FROM DM.C)
) sub1
Left Outer join (Top 2)
ItemID
r2_ItemPrice
r1_ItemPrice
207106
8555.65
13717.01
972304
11165
11879.26
Right Outer join (Top 2)
ItemID
r2_ItemPrice
r1_ItemPrice
207106
8555.65
13717.01
972304
11165
11879.26
LEFT join (Top 2)
ItemID
r2_ItemPrice
r1_ItemPrice
207106
8555.65
13717.01
972304
11165
11879.26
RIGHT join (Top 2)
ItemID
r2_ItemPrice
r1_ItemPrice
207106
8555.65
13717.01
972304
11165
11879.26
FULL outer join (Top 2)
ItemID
r2_ItemPrice
r1_ItemPrice
207106
8555.65
13717.01
972304
11165
11879.26
I've tried to remove all where clause and use AND clause as a filter to no avail. Both right outer join and inner join is showing.

Related

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

trying to modifying a multi join query with issues

I have a simplified query shown below, that does mulitple joins. I'm trying to add a field to be selected but I am unable to find a good way of joining it without changing the number of records that come up...
SELECT tblApp.AppID
,'Type' = tblRef.Label
,'Status' = tblRef2.Label
FROM (
(
(
tblApp LEFT JOIN tblAppExt ON tblApp.AppID = tblAppExt.AppID
) LEFT JOIN tblRef ON tblApp.AppTypeID = tblReferenceData.ID
) LEFT JOIN tblRef tblRef2 ON tblApp.AppStatusID = tblRef2.ID
)
As is - I'm getting 149 results, if I try to Join it in any way, I get like 10 time fold the number of records. All I'm hoping to do is be able to SELECt another field. I'm hoping to join tblAppExt2 that has AppID just like the other tables in the FROM part of the query, so my goal would basically be to do this:
SELECT tblApp.AppID
,'Type' = tblRef.Label
,'Status' = tblRef2.Label
,'NewField' = tblAppExt2.NewField
First thing to try is DISTINCT:
SELECT DISTINCT
tblApp.AppID
, [Type] = tblRef.Label
, [Status] = tblRef2.Label
, [NewField] = tblAppExt2.NewField
FROM tblApp
LEFT JOIN tblAppExt
ON tblApp.AppID = tblAppExt.AppID
LEFT JOIN tblRef
ON tblApp.AppTypeID = tblReferenceData.ID
LEFT JOIN tblRef tblRef2
ON tblApp.AppStatusID = tblRef2.ID
LEFT JOIN tblAppExt2.NewField
ON something = somethingElse ;
If that doesn't work, it means there are multiple different values for [NewField] and you'll need to tell it how to select the correct one. For example, to take the most recent [NewField] you can use a CTE with the ROW_NUMBER function:
; WITH AllRecords
AS (
SELECT DISTINCT
tblApp.AppID
, [Type] = tblRef.Label
, [Status] = tblRef2.Label
, [NewField] = tblAppExt2.NewField
, MyRank = ROW_NUMBER() OVER(PARTITION BY tblApp.ID ORDER BY tblAppExt2.DateEntered DESC)
FROM tblApp
LEFT JOIN tblAppExt
ON tblApp.AppID = tblAppExt.AppID
LEFT JOIN tblRef
ON tblApp.AppTypeID = tblReferenceData.ID
LEFT JOIN tblRef tblRef2
ON tblApp.AppStatusID = tblRef2.ID
LEFT JOIN tblAppExt2.NewField
ON something = somethingElse
)
SELECT *
FROM AllRecords
WHERE AllRecords.MyRank = 1 ;
You can use outer apply or correlated subquery :
SELECT tblApp.AppID, tblRef.Label as [Type], tblRef2.Label as [Status],
tappext.NewField
FROM tblApp tapp LEFT JOIN
tblAppExt tex
ON tapp.AppID = tex.AppID LEFT JOIN
tblRef tref
ON tapp.AppTypeID = tref.ID LEFT JOIN
tblRef tblRef2
ON tapp.AppStatusID = tblRef2.ID OUTER APPLY
( SELECT TOP (1) tappext.*
FROM tblAppExt2 tappext
WHERE tapp.AppID = AppID
ORDER BY ??
) tappext;

DISTINCT return same ID two times wrongly

This is my SQL query:
SELECT DISTINCT(ItemId), TCode, PartNumber,ModelNumber, ItemUOM
FROM #Results
This query returns:
ItemId TCode Source PartNumber ModelNumber ItemUOM
-----------------------------------------------------------------
1024 1000 NULL NULL EA
1024 1000 FLEX FLEX EA
#Result is a temp table I have used left join in that query
Why does SELECT DISTINCT return the same ItemID 1024 twice?
SELECT DISTCINT(I.ItemId),
(DENSE_RANK() OVER(ORDER BY I.ItemId ASC)) AS RowNumber,
(I.TCode), E.Name AS Source,
I.GoldenRecordNumber AS GoldenRecordNo, I.ItemCode AS MMRefNo,
I.ShortDescription AS ShortText, I.LongDescription AS POText,
Suppliers.Description AS Manufacturer, Suppliers.Name AS ManufacturerCode,
Suppliers.Abbreviation AS ManufacturerAbbr,
ItemSuppliers.ReferenceNo AS PartNumber, ItemSuppliers.ReferenceNo AS ModelNumber,
UOM.Name AS ItemUOM, MG.Name AS PSGC,
NM.Noun AS ClassName, NM.LongAbbrevation AS ClassDescription
INTO
#Results
FROM
Items I
LEFT JOIN
ItemSuppliers ON I.ItemId = ItemSuppliers.ItemsId
LEFT JOIN
Suppliers ON ItemSuppliers.ManufacturerId = Suppliers.SupplierId
LEFT JOIN
UnitOfMeasurement UOM ON UOM.UOMId = I.UOMId
LEFT JOIN
MaterialGroup MG ON MG.MaterialGroupId = I.MaterialGroupId
LEFT JOIN
NounModifiers NM ON NM.NounModifierId = I.NounModifierId
LEFT JOIN
AutoClass AC ON AC.ClassName = NM.Noun
LEFT JOIN
ERP E ON E.ERPId = I.ERPName
LEFT JOIN
NounModifierAttributes NMA ON NMA.NounModifierId =
NM.NounModifierId
LEFT JOIN
Attributes A ON A.AttributeId = NMA.AttributeId
LEFT JOIN
ItemAttributes IA ON IA.ItemId = I.ItemId
WHERE
(I.ItemCode LIKE '%'+'2001010088'+'%' )
SELECT 'Int' = COUNT(distinct(ItemId))
FROM #Results
WHERE (TCode IS NOT NULL OR MMRefNo IS NOT NULL)
SELECT DISTINCT(ItemId),
TCode, Source, GoldenRecordNo, MMRefNo, ShortText, POText,
Manufacturer, ManufacturerCode, ManufacturerAbbr, PartNumber, ModelNumber,
ItemUOM, PSGC, ClassName, ClassDescription
FROM
#Results
WHERE
(TCode IS NOT NULL OR MMRefNo IS NOT NULL)
AND RowNumber BETWEEN (1-1)*100 + 1 AND (((1-1) * 100 + 1) + 100) - 1
DROP TABLE #Results
if you are convinced the rows which are selected can be grouped together then it should work fine.
1. but if rows are having different data then distinct will not help.
2. use ltrim,rtrim to remove leading and trailing spaces.
example: distinct(ltrim(rtrim(ItemId)))
this will help if it due to spaces or for junk values
The behavior of DISTINCT works as expected. For instance, you could use GROUP BY clause to group them by ItemId, TCode to get top most records
SELECT
ItemId, TCode,
MAX(PartNumber) PartNumber, MAX(ModelNumber) ModelNumber,
MAX(ItemUOM), ...
FROM #Results
GROUP BY ItemId, TCode
In case any failure in GROUP BY clause use ranking function to assign the rank and get the record based on rank value.

SQL: Linking a Count to a specific value through multiple tables

I'm trying to link a COUNT to a specific value across several tables in a SQL Server Database. In this case the tables only share values through correlation. I am returning the values I want but the COUNT is counting everything in a given project not just the ones linked to their work items.
SELECT
[d].[Id]
,COUNT([t].[ItemId]) AS ItemCount
,[d].[ItemName]
FROM
[dbo].[Project_Map] [rm] WITH (NOLOCK)
INNER JOIN
[dbo].[WorkProjects] [r] WITH (NOLOCK)
ON [r].[DomainId] = [rm].[DomainId]
AND [r].[ProjectId] = [rm].[ProjectId]
AND [r].[ReleaseId] = [rm].[ReleaseId]
INNER JOIN
[dbo].[Items] [d] WITH (NOLOCK)
ON [d].[DomainId] = [r].[DomainId]
AND [d].[ProjectId] = [r].[ProjectId]
AND [d].[ReleaseId] = [r].[ReleaseId]
INNER JOIN [dbo].[Projects] [p] with (NOLOCK)
ON r.DomainId = p.DomainId
AND r.ProjectId = p.ProjectId
INNER JOIN [dbo].[Tests] [t] with (NOLOCK)
ON p.DomainId = t.DomainId
AND p.ProjectId = t.ProjectId
INNER JOIN
(
SELECT [Id], MAX([LastModifiedDate]) AS MostRecent
FROM Items
Group By [Id]
) AS updatedItem
ON updatedItem.Id = d.Id
INNER JOIN
[dbo].[WorkItemStates] [ds] WITH (NOLOCK)
ON [ds].[ItemStateName] = [d].[ItemStatus]
WHERE
d.Id = 111111
AND d.UserCategory Like 'SOMESTRING'
GROUP BY d.Id, d.ItemName
RETURNS: In this case the count should be 1 but it returns the count for the entire project.
ID COUNT ITEMNAME
86 5169 SOME NAME
173 5169 SOME NAME
170 5169 SOME NAME
Am I missing a join somewhere?
Currently, your counts are counting all JOIN instances and not just distinct Item level records. Consider turning your Item unit level join into an aggregate query join and include the count field in outer grouping:
Specifically, change:
INNER JOIN [dbo].[Tests] [t] with (NOLOCK)
ON p.DomainId = t.DomainId
AND p.ProjectId = t.ProjectId
Into:
INNER JOIN
(SELECT t.DomaindId, t.ProjectId, Count(*) As ItemCount
FROM [dbo].[Tests] t
GROUP BY t.DomaindId, t.ProjectId) agg
ON p.DomainId = agg.DomainId
AND p.ProjectId = agg.ProjectId
And then the outer query structure becomes:
SELECT
[d].[Id]
,agg.ItemCount
,[d].[ItemName]
FROM
...
GROUP BY
[d].[Id]
,agg.ItemCount
,[d].[ItemName]
Interestingly, you already do such an aggregate query join but never use that derived table updateItem or the field MostRecent.

Distinct on id with ordering by possible duplicate names

I have the following requisites for a query:
Needs to ordered on a inner joined table (see from_products_products below),
Allow duplicates names on from_products_products
It cannot return duplicates records on the origin table (distinct on products.id).
The following query will eliminate the duplicate names, which is not desired, as I had to put a distinct on from_products_products.name because of the use in order by:
SELECT DISTINCT ON (from_products_products.name, products.id) "products".* FROM "products"
INNER JOIN "suppliers_plugin_source_products" ON "suppliers_plugin_source_products"."to_product_id" = "products"."id"
INNER JOIN "products" "from_products_products" ON "from_products_products"."id" = "suppliers_plugin_source_products"."from_product_id"
INNER JOIN "suppliers_plugin_source_products" "sources_from_products_products_join" ON "sources_from_products_products_join"."to_product_id" = "products"."id"
INNER JOIN "suppliers_plugin_suppliers" ON "suppliers_plugin_suppliers"."id" = "sources_from_products_products_join"."supplier_id"
WHERE "products"."profile_id" = 45781 AND (("products"."type" IN ('SuppliersPlugin::DistributedProduct') OR "products"."type" IS NULL)) AND (products.archived <> true)
ORDER BY from_products_products.name ASC, products.id
Using GROUP BY has the same effect and also don't remove duplicates;
The original query that gives duplicate products when the INNER JOIN doesn't match any product:
SELECT "products".* FROM "products"
INNER JOIN "suppliers_plugin_source_products" ON "suppliers_plugin_source_products"."to_product_id" = "products"."id"
INNER JOIN "products" "from_products_products" ON "from_products_products"."id" = "suppliers_plugin_source_products"."from_product_id"
INNER JOIN "suppliers_plugin_source_products" "sources_from_products_products_join" ON "sources_from_products_products_join"."to_product_id" = "products"."id"
INNER JOIN "suppliers_plugin_suppliers" ON "suppliers_plugin_suppliers"."id" = "sources_from_products_products_join"."supplier_id"
WHERE "products"."profile_id" = 45781 AND (("products"."type" IN ('SuppliersPlugin::DistributedProduct') OR "products"."type" IS NULL)) AND (products.archived <> true)
ORDER BY from_products_products.name ASC
So, how to overcome this on PostgreSQL?
PS: This is part of open-source software Noosfero-ecosol
Does this do what you want?
with t as (
SELECT DISTINCT ON (products.id) "products".*,
from_products_products.name as from_products_name
FROM "products"
INNER JOIN "suppliers_plugin_source_products" ON "suppliers_plugin_source_products"."to_product_id" = "products"."id"
INNER JOIN "products" "from_products_products" ON "from_products_products"."id" = "suppliers_plugin_source_products"."from_product_id"
INNER JOIN "suppliers_plugin_source_products" "sources_from_products_products_join" ON "sources_from_products_products_join"."to_product_id" = "products"."id"
INNER JOIN "suppliers_plugin_suppliers" ON "suppliers_plugin_suppliers"."id" = "sources_from_products_products_join"."supplier_id"
WHERE "products"."profile_id" = 45781 AND (("products"."type" IN ('SuppliersPlugin::DistributedProduct') OR "products"."type" IS NULL)) AND (products.archived <> true)
ORDER BY products.id
)
select t.*
from t
order by from_products_name
It seems to meet your requirements.
EDIT:
If the above does what you want, I can think of five options:
The above using a CTE.
Basically the same logic, using a subquery.
Using window functions, which is structurally very similar.
Using group by.
Using a where clause for the filtering logic.
Here is the group by method:
SELECT "products".*,
MIN(from_products_products.name) as from_products_name
FROM "products"
INNER JOIN "suppliers_plugin_source_products" ON "suppliers_plugin_source_products"."to_product_id" = "products"."id"
INNER JOIN "products" "from_products_products" ON "from_products_products"."id" = "suppliers_plugin_source_products"."from_product_id"
INNER JOIN "suppliers_plugin_source_products" "sources_from_products_products_join" ON "sources_from_products_products_join"."to_product_id" = "products"."id"
INNER JOIN "suppliers_plugin_suppliers" ON "suppliers_plugin_suppliers"."id" = "sources_from_products_products_join"."supplier_id"
WHERE "products"."profile_id" = 45781 AND (("products"."type" IN ('SuppliersPlugin::DistributedProduct') OR "products"."type" IS NULL)) AND (products.archived <> true)
GROUP BY products.id
ORDER BY from_products_name;
This form depends on products.id being declared as a primary key. Alternatively, you can put all the columns from that table in the group by.
Rewriting (simplifying the aliases) yields:
SELECT p1.*
FROM products p1
INNER JOIN suppliers_plugin_source_products spsp
ON spsp.to_product_id = p1.id
INNER JOIN products p2
ON p2.id = spsp.from_product_id
INNER JOIN suppliers_plugin_source_products spsp2
ON spsp2.to_product_id = p1.id -- <<-- Huh?
INNER JOIN suppliers_plugin_suppliers sps
ON sps.id = spsp2.supplier_id
WHERE p1.profile_id = 45781
AND (p1."type" IN ('SuppliersPlugin::DistributedProduct') OR p1."type" IS NULL)
AND p1.archived <> true
ORDER BY p2.name ASC -- <<-- Huh?
;
The outer query only refers to the product tables p1 and p2.
Assuming that JOINing the "suppliers_plugin_source_products" table twice was unintentional, this can be reduced to:
SELECT p1.*
FROM products p1
JOIN products p2
ON EXISTS (
SELECT * FROM suppliers_plugin_source_products spsp
-- the next line might not be necessary ...
INNER JOIN suppliers_plugin_suppliers sps ON sps.id = spsp.supplier_id
WHERE spsp.to_product_id = p1.id
AND spsp.from_product_id = p2.id
)
WHERE p1.profile_id = 45781
AND (p1."type" IN ('SuppliersPlugin::DistributedProduct') OR p1."type" IS NULL)
AND p1.archived <> true
ORDER BY p2.name ASC
;