How sort by counter , but haven't counter - SQL server - sql

I have one query like
SELECT COUNT(ShoppingProductFeature.ShoppingFeatureId) as countShow,ShoppingProductFeature.ShoppingFeatureId as valueId, ShoppingProductFeature.ShoppingParentFeatureId as attrId, ShoppingFeatureLanguage.Title as attrName, ShoppingFeatureLanguage_1.Title AS valueName
FROM ShoppingFeatureLanguage INNER JOIN ShoppingProductFeature INNER JOIN ShoppingFeatureLanguage AS ShoppingFeatureLanguage_1 ON ShoppingProductFeature.ShoppingFeatureId = ShoppingFeatureLanguage_1.ShoppingFeatureId ON ShoppingFeatureLanguage.ShoppingFeatureId = ShoppingProductFeature.ShoppingParentFeatureId INNER JOIN ShoppingFeature ON ShoppingProductFeature.ShoppingFeatureId = ShoppingFeature.ShoppingFeatureId
INNER JOIN Product ON ShoppingProductFeature.ProductId = Product.ProductId
INNER JOIN Company ON Product.CompanyId = Company.CompanyId
GROUP BY ShoppingProductFeature.ShoppingFeatureId, ShoppingProductFeature.ShoppingParentFeatureId, ShoppingFeatureLanguage.Title, ShoppingFeatureLanguage_1.Title, ShoppingFeatureLanguage_1.LanguageId, ShoppingFeatureLanguage.LanguageId, ShoppingFeature.isConfirmed,Product.MoneyId,Product.TypeId , Company.GeoId , Product.ShoppinGroupId
HAVING (ShoppingFeatureLanguage_1.LanguageId = 2) AND (ShoppingFeatureLanguage.LanguageId = 2) AND (ShoppingFeature.isConfirmed = 1) and (Product.TypeId = 11) and Product.ShoppinGroupId like N'mn%' and Company.GeoId like N'aa%'
ORDER BY countShow DESC
As it clear I have to sort it by countShow and I have to call COUNT(ShoppingProductFeature.ShoppingFeatureId) to select because I can't add it to Order By
So the result is something like this
enter image description here
How can I distinct data or sort them without duplicate data

Try some thing like below..
SELECT
COUNT(ShoppingProductFeature.ShoppingFeatureId) as countShow,ShoppingProductFeature.ShoppingFeatureId,.....
FROM ShoppingFeatureLanguage
INNER JOIN ShoppingProductFeature
INNER JOIN ShoppingFeatureLanguage AS ShoppingFeatureLanguage_1 ON ...
INNER JOIN Product ON ShoppingProductFeature.ProductId = Product.ProductId
GROUP BY ShoppingProductFeature.ShoppingFeatureId,.....
HAVING (ShoppingFeatureLanguage_1.LanguageId = 2) AND (ShoppingFeatureLanguage.LanguageId = 2) AND (ShoppingFeature.isConfirmed = 1) and (Product.TypeId = 11) and Product.ShoppinGroupId =5 and Company.GeoId=45
ORDER BY countShow DESC

Related

SQL - SUM TotalValue returning a null with LEFT JOIN Clause

I'd to like SUM a TotalValue column based on Vendor and logged in user. I completely returning a right value of other info in logged user and the connected vendor, the problem is the SUM of TotalValue column is returning a null value. am I missing something?
This is what I've already tried:
SELECT ,v.VendorName ,
u.Product ,
v.[Description] ,
v.Status ,
SUM(cpm.TotalValue) AS TotalValue
FROM Vendor v
LEFT JOIN [ProductContract] c ON v.VendorId = c.VendorId
AND c.[Status] = 4
AND c.ProductContractId IN
(SELECT con.ProductContractId
FROM [ProductContract] con
INNER JOIN [ProductContractPermission] cp ON cp.ProductContractId = con.ProductContractId
WHERE cp.UserInfoId = #UserInfoId)
LEFT JOIN ProductContractPaymentMenu cpm ON c.ProductContractId = cpm.ProductContractId
AND c.[Status] = 4
AND c.VendorId = #VendorId
LEFT JOIN VendorContact vc ON v.VendorId = vc.VendorId
AND vc.[Type] = 1
LEFT JOIN UserInfo u ON vc.UserInfoId = u.UserInfoId
WHERE v.VendorId IN
(SELECT VendorId
FROM ClientVendor
WHERE ClientId = #VendorId)
GROUP BY v.VendorName,
u.Product,
v.[Description],
v.Status,
cpm.TotalValue
ORDER BY v.[Status],
v.CreatedOn
Seems that you want to apply an aggregate filter, this is the famous HAVING clause:
...
GROUP BY v.VendorName,
u.Product,
v.[Description],
v.Status,
cpm.TotalValue
HAVING
SUM(cpm.TotalValue) > 0
ORDER BY v.[Status],
v.CreatedOn
Hi i think you have to add ISNULL(value,defaultvalue) because cpm table was on left join and it can be null.
SELECT v.VendorName ,
u.Product ,
v.[Description] ,
v.Status ,
SUM(ISNULL(cpm.TotalValue,0)) AS TotalValue
FROM Vendor v
LEFT JOIN [ProductContract] c ON v.VendorId = c.VendorId
AND c.[Status] = 4
AND c.ProductContractId IN
(SELECT con.ProductContractId
FROM [ProductContract] con
INNER JOIN [ProductContractPermission] cp ON cp.ProductContractId = con.ProductContractId
WHERE cp.UserInfoId = #UserInfoId)
LEFT JOIN ProductContractPaymentMenu cpm ON c.ProductContractId = cpm.ProductContractId
AND c.[Status] = 4
AND c.VendorId = #VendorId
LEFT JOIN VendorContact vc ON v.VendorId = vc.VendorId
AND vc.[Type] = 1
LEFT JOIN UserInfo u ON vc.UserInfoId = u.UserInfoId
WHERE v.VendorId IN
(SELECT VendorId
FROM ClientVendor
WHERE ClientId = #VendorId)
GROUP BY v.VendorName,
u.Product,
v.[Description],
v.Status,
cpm.TotalValue
ORDER BY v.[Status],
v.CreatedOn
https://learn.microsoft.com/en-us/sql/t-sql/functions/isnull-transact-sql?view=sql-server-2017
Edit: other point you have miss ',' in your query after the SELECT.
Your left join on ProductContractPaymentMenu may not always get an item, so cpm.TotalValue can be NULL sometimes. When you use SUM and when one value is NULL then the result will be NULL. You might rewrite that part as:
SUM(ISNULL(cpm.TotalValue, 0)) AS TotalValue
In that case, it will treat non-existing records as value 0.

How to join this query based on condition?

I have a query like below to join 6 table.
select usr.userid,usr.firstName,usr.middleName,usr.lastName,nuser.GRAND_FATHER_NAME,nco untry.NAME_AR,ncountry.NAME_EN,ncase.START_DATE
from User_ usr
inner join TBL_NAFETHAH_USER nuser
On nuser.USER_ID = usr.userId
inner join TBL_NAFETHAH_COUNTRY ncountry
on nuser.NATIONALITY = ncountry.ID
inner join TBL_NAFETHAH_CASE ncase
on usr.userId = ncase.inmate_id
inner join TBL_NAFETHAH_CASE_STATUS ncasestatus
ON ncase.CASE_STATUS_ID = ncasestatus.CASE_STATUS_ID
and ncasestatus.CASE_STATUS IN (1,2))
inner join TBL_NAFETHAH_CASE_STAGE ncasestage
on ncasestage.CASE_STAGE_ID = ncase.CASE_STAGE_ID
inner join TBL_NAFETHAH_USER_IDENTIFICATION uident
on ( (usr.userId = uident.USER_ID and uident.ID_TYPE = 1) or (usr.userId = uident.USER_ID and uident.ID_TYPE = 2) )
inner join TBL_NAFETHAH_LOOKUP_VALUE nlookup
on nlookup.LOOKUP_KEY = uident.ID_TYPE
and nlookup.CATEGORY_ID = 9
inner join TBL_NAFETHAH_LOOKUP_VALUE nlookup2
on nlookup2.LOOKUP_KEY = ncasestage.CASE_STAGE
and nlookup2.CATEGORY_ID = 15
where nuser.MAKE_PUBLIC = 1
I want to put one more condition in this line
inner join TBL_NAFETHAH_USER_IDENTIFICATION uident on ( (usr.userId = uident.USER_ID and uident.ID_TYPE = 1) or (usr.userId = uident.USER_ID and uident.ID_TYPE = 2) )
If this condition does not met, ie empty (usr.userId = uident.USER_ID and uident.ID_TYPE = 1) or (usr.userId = uident.USER_ID and uident.ID_TYPE = 2)m then I have to add another condition (usr.userId = uident.USER_ID) and if it returns muliple row only take first row.
How to achieve it?
If you want to omit missing records from the TBL_NAFETHAH_USER_IDENTIFICATION table then INNER JOIN a sub query that returns the first record that meets the criteria with a useful ORDER BY.
inner join
(
SELECT TOP(1) * FROM TBL_NAFETHAH_USER_IDENTIFICATION uident
WHERE usr.userId = uident.USER_ID --AND ID_TYPE IN(1, 2)
ORDER BY ID_TYPE
)
uident ON usr.userId = uident.USER_ID
If you want to include records without a match from the TBL_NAFETHAH_USER_IDENTIFICATION table then LEFT OUTER JOIN a sub query that returns the first record that meets the criteria with a useful ORDER BY.
left outer join
(
SELECT TOP(1) * FROM TBL_NAFETHAH_USER_IDENTIFICATION uident
WHERE usr.userId = uident.USER_ID ID_TYPE IN(1, 2)
ORDER BY <SomeValue>
)
uident ON 1=1
NOTE : If there will always be a record in the TBL_NAFETHAH_USER_IDENTIFICATION for each user then you can order by ID_TYPE and take the first row. If 1 and 2 are the first two values in ID_TYPE, this will guarantee that if there is a type of 1 or 2 then it will come first. If you have a type of 0,-1,A, B, etc, then you will have to add a virtual rank column via another sub query.

How to use group by only for some columns in sql Query?

The following query returns 550 records, which I am then grouping by some columns in the controller via linq. However, how can I achieve the "group by" logic in the SQL query itself? Additionally, post-grouping, I need to show only 150 results to the user.
Current SQL query:
SELECT DISTINCT
l.Id AS LoadId
, l.LoadTrackingNumber AS LoadDisplayId
, planningType.Text AS PlanningType
, loadStatus.Id AS StatusId
, loadWorkRequest.Id AS LoadRequestId
, loadStatus.Text AS Status
, routeIds.RouteIdentifier AS RouteName
, planRequest.Id AS PlanId
, originPartyRole.Id AS OriginId
, originParty.Id AS OriginPartyId
, originParty.LegalName AS Origin
, destinationPartyRole.Id AS DestinationId
, destinationParty.Id AS DestinationPartyId
, destinationParty.LegalName AS Destination
, COALESCE(firstSegmentLocation.Window_Start, originLocation.Window_Start) AS StartDate
, COALESCE(firstSegmentLocation.Window_Start, originLocation.Window_Start) AS BeginDate
, destLocation.Window_Finish AS EndDate
AS Number
FROM Domain.Loads (NOLOCK) AS l
INNER JOIN dbo.Lists (NOLOCK) AS loadStatus ON l.LoadStatusId = loadStatus.Id
INNER JOIN Domain.Routes (NOLOCK) AS routeIds ON routeIds.Id = l.RouteId
INNER JOIN Domain.BaseRequests (NOLOCK) AS loadWorkRequest ON loadWorkRequest.LoadId = l.Id
INNER JOIN Domain.BaseRequests (NOLOCK) AS planRequest ON planRequest.Id = loadWorkRequest.ParentWorkRequestId
INNER JOIN Domain.Schedules AS planSchedule ON planSchedule.Id = planRequest.ScheduleId
INNER JOIN Domain.Segments (NOLOCK) os on os.RouteId = routeIds.Id AND os.[Order] = 0
INNER JOIN Domain.LocationDetails (NOLOCK) AS originLocation ON originLocation.Id = os.DestinationId
INNER JOIN dbo.EntityRoles (NOLOCK) AS originPartyRole ON originPartyRole.Id = originLocation.DockRoleId
INNER JOIN dbo.Entities (NOLOCK) AS originParty ON originParty.Id = originPartyRole.PartyId
INNER JOIN Domain.LocationDetails (NOLOCK) AS destLocation ON destLocation.Id = routeIds.DestinationFacilityLocationId
INNER JOIN dbo.EntityRoles (NOLOCK) AS destinationPartyRole ON destinationPartyRole.Id = destLocation.DockRoleId
INNER JOIN dbo.Entities (NOLOCK) AS destinationParty ON destinationParty.Id = destinationPartyRole.PartyId
INNER JOIN dbo.TransportationModes (NOLOCK) lictm on lictm.Id = l.LoadInstanceCarrierModeId
INNER JOIN dbo.EntityRoles (NOLOCK) AS carrierPartyRole ON lictm.CarrierId = carrierPartyRole.Id
INNER JOIN dbo.Entities (NOLOCK) AS carrier ON carrierPartyRole.PartyId = carrier.Id
INNER JOIN dbo.EntityRoles (NOLOCK) AS respPartyRole ON l.ResponsiblePartyId = respPartyRole.Id
INNER JOIN dbo.Entities (NOLOCK) AS respParty ON respPartyRole.PartyId = respParty.Id
INNER JOIN Domain.LoadOrders (NOLOCK) lo ON lo.LoadInstanceId = l.Id
INNER JOIN Domain.Orders (NOLOCK) AS o ON lo.OrderInstanceId = o.Id
INNER JOIN Domain.BaseRequests (NOLOCK) AS loadRequest ON loadRequest.LoadId = l.Id
--Load Start Date
LEFT JOIN Domain.Segments (NOLOCK) AS segment ON segment.RouteId = l.RouteId AND segment.[Order] = 0
LEFT JOIN Domain.LocationDetails (NOLOCK) AS firstSegmentLocation ON firstSegmentLocation.Id = segment.DestinationId
LEFT JOIN dbo.Lists (NOLOCK) AS planningType ON l.PlanningTypeId = planningType.Id
LEFT JOIN dbo.EntityRoles (NOLOCK) AS billToRole ON o.BillToId = billToRole.Id
LEFT JOIN dbo.Entities (NOLOCK) AS billTo ON billToRole.PartyId = billTo.Id
WHERE o.CustomerId in (34236) AND originLocation.Window_Start >= '07/19/2015 00:00:00' AND originLocation.Window_Start < '07/25/2015 23:59:59' AND l.IsHistoricalLoad = 0
AND loadStatus.Id in (285, 286,289,611,290)
AND loadWorkRequest.ParentWorkRequestId IS NOT NULL
AND routeIds.RouteIdentifier IS NOT NULL
AND (planSchedule.EndDate IS NULL OR (planSchedule.EndDate is not null and CAST(CONVERT(varchar(10), planSchedule.EndDate,101) as datetime) > CAST(CONVERT(varchar(10),GETDATE(),101) as datetime))) ORDER BY l.Id DESC
linq:
//Get custom grouped data
var loadRequest = (from lq in returnList
let loadDisplayId = lq.LoadDisplayId
let origin = lq.OriginId //get this origin for route
let destination = lq.DestinationId // get this destination for route
group lq by new
{
RouteId = lq.RouteName,
PlanId = lq.PlanId,
Origin = lq.OriginId,
Destination = lq.DestinationId
}
into grp
select new
{
RouteId = grp.Key.RouteId,
PlanId = grp.Key.PlanId,
Origin = grp.Key.Origin,
Destination = grp.Key.Destination,
Loads = (from l in grp select l)
}).OrderBy(x => x.Origin).ToList();
I'm guessing you want to Group By column 1 but include columns 2 and 3 in your Select. Using a Group By you cannot do this. However, you can do this using a T-SQL Windowing function using the OVER() operator. Since you don't say how you want to aggregate, I cannot provide an example. But look at T-SQL Windowing functions. This article might help you get started.
One important thing you need to understand about GROUP BY is that you must assume that there are multiple values in every column outside of the GROUP BY list. In your case, you must assume that for each value of Column1 there would be multiple values of Column2 and Column3, all considered as a single group.
If you want your query to process any of these columns, you must specify what to do about these multiple values.
Here are some choices you have:
Pick the smallest or the largest value for a column in a group - use MIN(...) or MAX(...) aggregator for that
Count non-NULL items in a group - use COUNT(...)
Produce an average of non-NULL values in a group - use AVG(...)
For example, if you would like to find the smallest Column2 and an average of Column3 for each value of Column1, your query would look like this:
select
Column1, MIN(Column2), AVG(Column3)
from
TableName
group by
Column1

SQL Server, insert value to variable and sort

I need to sort the results of a query after insert a value to a variable.
I am trying to sort according to 'RowId' but its not valid in my case.
Below is my query, how can I make it work?
Thanks.
SELECT TOP 1 #NumOfProducts = ROW_NUMBER() OVER(ORDER BY Products.Id) AS RowId
FROM Cities INNER JOIN
CitiesInLanguages ON Cities.Id = CitiesInLanguages.CityId INNER JOIN
ShopsInCities ON Cities.Id = ShopsInCities.CityId INNER JOIN
Categories INNER JOIN
ProductstInCategories ON Categories.Id = ProductstInCategories.CategoryId INNER JOIN
Products ON ProductstInCategories.ProductId = Products.Id INNER JOIN
ProductsInProdutGroup ON Products.Id = ProductsInProdutGroup.ProductId INNER JOIN
ProductsGroups ON ProductsInProdutGroup.ProductGroupId = ProductsGroups.Id INNER JOIN
ShopsInProductsGroup ON ProductsGroups.Id = ShopsInProductsGroup.ProductGroupId INNER JOIN
aspnet_Users ON ShopsInProductsGroup.ShopId = aspnet_Users.UserId ON ShopsInCities.ShopId = aspnet_Users.UserId INNER JOIN
ProductsNamesInLanguages ON Products.Id = ProductsNamesInLanguages.ProductId INNER JOIN
UsersInfo ON aspnet_Users.UserId = UsersInfo.UserId INNER JOIN
ProductOptions ON Products.Id = ProductOptions.ProductId INNER JOIN
ProductOptionsInLanguages ON ProductOptions.Id = ProductOptionsInLanguages.ProductOptionId INNER JOIN
ProductFiles ON Products.Id = ProductFiles.ProductId INNER JOIN
ProductsInOccasions ON Products.Id = ProductsInOccasions.ProductId INNER JOIN
Occasions ON ProductsInOccasions.OccasionId = Occasions.Id INNER JOIN
OccasionsInLanguages ON Occasions.Id = OccasionsInLanguages.OccasionId
WHERE (Products.IsAddition = 0) AND (Categories.IsEnable = 1) AND (Products.IsEnable = 1) AND (ProductsGroups.IsEnable = 1) AND (Cities.IsEnable = 1) AND
(ShopsInProductsGroup.IsEnable = 1) AND (CitiesInLanguages.CityName = #CityName) AND (ProductsNamesInLanguages.LanguageId = #languageId) AND
(Categories.Id = #CategoryId) AND (ProductOptions.IsEnable = 1) AND (ProductFiles.IsEnable = 1)
group by Products.Id, ProductsNamesInLanguages.ProductName, UsersInfo.Name
Order By RowId
With edit try this:
SELECT TOP 1 #NumOfProducts = ROW_NUMBER() OVER(ORDER BY Products.Id),
ROW_NUMBER() OVER(ORDER BY Products.Id) AS RowId
or try
ORDER BY ROW_NUMBER() OVER(ORDER BY Products.Id)
I'd have to test but I thik both will work.
The problem is that rowid is not in any of the group by items.
You could order by Products.id. If rowid is going to be the same for each one you could order by max(rowid) or min(rowid) or add rowid to the group by statement.
Are you trying to find the ID of the most recently inserted row? You want
SELECT Scope_Identity()
Edit
*I am trying to get the max row id of ROW_NUMBER()*
Wrap your query in
SELECT #NumOfProducts = Max(RowID) FROM
( [your query here] ) v
Alternately, a SELECT COUNT... query may provide the answer

Merge these two queries into a single query

I have the following queries:
SELECT Sites.EDISID, Sites.[Name], (SUM(DLData.Quantity) / 8) AS TiedDispense
FROM Sites
JOIN UserSites
ON UserSites.EDISID = Sites.EDISID
JOIN Users
ON Users.[ID] = UserSites.UserID
JOIN MasterDates
ON MasterDates.EDISID = UserSites.EDISID
JOIN DLData
ON DLData.DownloadID = MasterDates.[ID]
JOIN Products
ON Products.[ID] = DLData.Product
LEFT JOIN SiteProductTies
ON SiteProductTies.EDISID = UserSites.EDISID
AND SiteProductTies.ProductID = Products.[ID]
LEFT JOIN SiteProductCategoryTies
ON SiteProductCategoryTies.EDISID = UserSites.EDISID
AND SiteProductCategoryTies.ProductCategoryID = Products.CategoryID
WHERE Users.[ID] = #UserID
AND (COALESCE(SiteProductTies.Tied, SiteProductCategoryTies.Tied, Products.Tied) = #Tied OR #Tied IS NULL)
AND MasterDates.[Date] BETWEEN #From AND #To
AND MasterDates.[Date] >= Sites.SiteOnline
GROUP BY Sites.EDISID, Sites.[Name]
SELECT Sites.EDISID, Sites.[Name], SUM(Delivery.Quantity) AS TiedDelivered
FROM Sites
JOIN UserSites
ON UserSites.EDISID = Sites.EDISID
JOIN Users
ON Users.[ID] = UserSites.UserID
JOIN MasterDates
ON MasterDates.EDISID = UserSites.EDISID
JOIN Delivery
ON Delivery.DeliveryID = MasterDates.[ID]
JOIN Products
ON Products.[ID] = Delivery.Product
LEFT JOIN SiteProductTies
ON SiteProductTies.EDISID = UserSites.EDISID
AND SiteProductTies.ProductID = Products.[ID]
LEFT JOIN SiteProductCategoryTies
ON SiteProductCategoryTies.EDISID = UserSites.EDISID
AND SiteProductCategoryTies.ProductCategoryID = Products.CategoryID
WHERE Users.[ID] = #UserID
AND (COALESCE(SiteProductTies.Tied, SiteProductCategoryTies.Tied, Products.Tied) = #Tied OR #Tied IS NULL)
AND MasterDates.[Date] BETWEEN #From AND #To
AND MasterDates.[Date] >= Sites.SiteOnline
GROUP BY Sites.EDISID, Sites.[Name]
As you can see they are very similar - only the lines regarding whether the query is for DLData or Delivery are different. One returns the total delivered the other returns the total dispensed.
Currently I am using them as two separate sub-queries in a third query. Singly they take approximately 1-2 seconds each. As two subqueries they are taking between 6 and 10 seconds (depending on load) and both return just 47 rows (though they are touching thousands of rows total).
I was thinking that combining them will give me a decent speed up - especially as this query will be called a lot.
However my attempts have failed as the number of rows change when I try to combine the two. I have tried various JOIN combinations but nothing returns the correct results.
Do the SO'ers have any suggestions?
you could try:
SELECT Sites.EDISID,
Sites.[Name],
(SUM(DLData.Quantity) / 8) AS TiedDispense,
SUM(Delivery.Quantity) AS TiedDelivered
FROM Sites
JOIN UserSites
ON UserSites.EDISID = Sites.EDISID
JOIN Users
ON Users.[ID] = UserSites.UserID
JOIN MasterDates
ON MasterDates.EDISID = UserSites.EDISID
JOIN DLData
ON DLData.DownloadID = MasterDates.[ID]
JOIN Products
ON Products.[ID] = DLData.Product
LEFT JOIN Delivery
ON Delivery.DeliveryID = MasterDates.[ID]
LEFT JOIN SiteProductTies
ON SiteProductTies.EDISID = UserSites.EDISID AND SiteProductTies.ProductID = Products.[ID]
LEFT JOIN SiteProductCategoryTies
ON SiteProductCategoryTies.EDISID = UserSites.EDISID
AND SiteProductCategoryTies.ProductCategoryID = Products.CategoryID
WHERE Users.[ID] = #UserID
AND (COALESCE(SiteProductTies.Tied, SiteProductCategoryTies.Tied, Products.Tied) = #Tied
OR #Tied IS NULL)
AND MasterDates.[Date] BETWEEN #From AND #To
AND MasterDates.[Date] >= Sites.SiteOnline
GROUP BY Sites.EDISID, Sites.[Name]
I did a left join but an Inner join might work depending on your data. I'd also check to make sure that all of those foreign key fields are indexed.
After a quick look at your query, I can't be sure if this is correct without understanding the business rules behind the data. However, you can give this a shot if you'd like:
SELECT
Sites.EDISID, Sites.[Name],
CASE WHEN Delivery.DeliveryID IS NULL THEN 0 ELSE SUM(Delivery.Quantity) END TiedDelivered,
CASE WHEN DLData.[ID] IS NULL THEN 0 ELSE (SUM(DLData.Quantity) / 8) END TiedDispense
FROM Sites
JOIN UserSites
ON UserSites.EDISID = Sites.EDISID
JOIN Users
ON Users.[ID] = UserSites.UserID
JOIN MasterDates
ON MasterDates.EDISID = UserSites.EDISID
LEFT JOIN Products
ON Products.[ID] = DLData.Product
LEFT JOIN DLData
ON DLData.DownloadID = MasterDates.[ID]
LEFT JOIN Delivery
ON Delivery.DeliveryID = MasterDates.[ID]
LEFT JOIN SiteProductTies
ON SiteProductTies.EDISID = UserSites.EDISID
AND SiteProductTies.ProductID = Products.[ID]
LEFT JOIN SiteProductCategoryTies
ON SiteProductCategoryTies.EDISID = UserSites.EDISID
AND SiteProductCategoryTies.ProductCategoryID = Products.CategoryID
WHERE Users.[ID] = #UserID
AND (COALESCE(SiteProductTies.Tied, SiteProductCategoryTies.Tied, Products.Tied) = #Tied OR #Tied IS NULL)
AND MasterDates.[Date] BETWEEN #From AND #To
AND MasterDates.[Date] >= Sites.SiteOnline
AND (DLData.[DownloadID] IS NOT NULL OR DELIVERY.DeliveryID IS NOT NULL)
GROUP BY Sites.EDISID, Sites.[Name]
one key to it is this part:
AND (DLData.[DownloadID] IS NOT NULL OR DELIVERY.DeliveryID IS NOT NULL)
Which is heavily based on assumptions of your business rules but might make up for extra rows returned by the two left joins. You can also play with something like this if you'd like:
AND ( TiedDelivered != 0 AND TiedDispense != 0)
hope this helps.
-steve
I wrote a dumb answer to this and it bugged me so I started looking into it a bit more - basically you want to put the group bys inside the joins. I haven't got time to edit your code but I think this example should get you there:
create table #prod(
prodid int,
prodamount int)
create table #del(
delid int,
delamount int)
create table #main(
id int,
name varchar(50))
insert into #main(id,name)
select 1, 'test 1'
union select 2, 'test 2'
union select 3, 'test 3'
union select 4, 'test 4'
insert into #prod(prodid,prodamount)
select 1, 10
union select 1, 20
union select 1, 30
union select 2, 5
insert into #del(delid,delamount)
select 1, 9
union select 1, 8
union select 3, 7
/** wrong **/
select m.id, m.name, isnull(sum(p.prodamount),0), isnull(sum(d.delamount),0)
from #main m
left join #prod p on p.prodid = m.id
left join #del d on d.delid = m.id
group by m.id, m.name
/** right! **/
select id, name, isnull(myprod.prodtot,0) as prodtot, isnull(mydel.deltot,0) as deltot
from #main
left join
(SELECT prodid, SUM(prodamount) AS prodtot
FROM #prod
GROUP BY prodid) myprod on #main.id = myprod.prodid
left join
(SELECT delid, SUM(delamount) AS deltot
FROM #del
GROUP BY delid) mydel on #main.id = mydel.delid
drop table #prod
drop table #del
drop table #main
Here's my rewrite of you queries into a single query:
SELECT t.edisid,
t.name,
SUM(dd.quantity) / 8 AS TiedDispense,
SUM(d.quantity) AS TiedDelivered
FROM SITES t
JOIN USERSITES us ON us.edisid = t.esisid
JOIN USERS u ON u.id = us.userid
JOIN MASTERDATES md ON md.edisid = us.edisid
AND md.date >= t.siteonline
LEFT JOIN DLDATA dd ON dd.downloadid = md.id
LEFT JOIN DELIVERY d ON d.deliveryid = md.id
JOIN PRODUCTS p ON p.id IN (dd.product, d.product)
LEFT JOIN SITEPRODUCTTIES spt ON spt.edisid = us.edisid
AND spt.productid = p.id
LEFT JOIN SITEPRODUCTCATEGORYTIES spct ON spct.edisid = us.edisid
AND spct.productcategoryid = p.categoryid
WHERE u.id = #UserID
AND (#Tied IS NULL OR COALESCE(spt.tied, spct.tied, p.tied) = #Tied)
AND md.date BETWEEN #From AND #To
GROUP BY t.edisid, t.name
Depending on your data, the JOINs to DLDATA and DELIVERY could be inner joins.
It'd be good to get in the habit of using table aliases.
Without wanting to sound overly stupid, but I guess a union is not going to help (would require a small change to a returned column name...)?