Count from another table with join - sql

How can I Count the Lending comments for each lending (the comments is on another table called "LendingComments" with a reference Column called "LendingId" ?
SELECT LendingStatus.Status, Products.Productname, Products.Serial_number, Deposits.Amount, Lendings.DeliveryDate, Lendings.Id AS LendingId, Products.Id AS ProductId FROM Lendings
LEFT JOIN Products ON Lendings.ProductId = Products.Id
LEFT JOIN LendingStatus ON Lendings.StatusId = LendingStatus.Id
LEFT JOIN Deposits ON Lendings.DepositId = Deposits.Id
WHERE PersonId = 561 ORDER BY DeliveryDate DESC

Maby like this (if I understand the question well enough)
SELECT
LendingStatus.Status, Products.Productname, Products.Serial_number,Deposits.Amount, Lendings.DeliveryDate, Lendings.Id AS LendingId, Products.Id AS ProductId, LendingComments.NumLendingComments
FROM Lendings
LEFT JOIN Products ON Lendings.ProductId = Products.Id
LEFT JOIN LendingStatus ON Lendings.StatusId = LendingStatus.Id
LEFT JOIN Deposits ON Lendings.DepositId = Deposits.Id
OUTER APPLY
(
SELECT
COUNT(*) AS NumLendingComments
FROM
LendingComments PL
WHERE
PL.LendingID = Lendings.LendingID
) AS LendingComments WHERE Personid = 561 ORDER BY DeliveryDate desc

Maybe this helps:
SELECT CommentCount = Sum(lc.comments)
OVER (
partition BY lc.id),
lendingstatus.status,
products.productname,
products.serial_number,
deposits.amount,
lendings.deliverydate,
lendings.id AS LendingId,
products.id AS ProductId
FROM lendings
LEFT JOIN products
ON lendings.productid = products.id
LEFT JOIN lendingstatus
ON lendings.statusid = lendingstatus.id
LEFT JOIN deposits
ON lendings.depositid = deposits.id
LEFT JOIN LendingComments lc
ON lc.LendingId = lendings.Lendings.Id
WHERE personid = 561
ORDER BY deliverydate DESC
However, you have not shown the PersonLendings table, have you?

Try this one -
SELECT ls.status
, p.Productname
, p.Serial_number
, d.AMOUNT
, l.DeliveryDate
, l.Id AS LendingId
, p.Id AS ProductId
, pl.cnt
FROM dbo.Lendings l
LEFT JOIN (
SELECT pl.LendingId, cnt = COUNT(pl.LendingComments)
FROM dbo.PersonLendings pl
GROUP BY pl.LendingId
) pl ON pl.LendingId = l.LendingId
LEFT JOIN dbo.Products p ON l.ProductId = p.Id
LEFT JOIN dbo.LendingStatus ls ON l.StatusId = ls.Id
LEFT JOIN dbo.Deposits d ON l.DepositId = d.Id
WHERE PersonID = 561
ORDER BY l.DeliveryDate DESC

Related

Oracle SQL How to Count Column Value Occurences and Group BY during joins

I'm working on another SQL query, trying to group a collection of records while doing a count and joining tables. See below for goal, current query, and attached scripts for building and populating tables.
Show all customers who have checked more books than DVDs. Display
customer name, total book checkouts and total DVD checkouts. Sort
results by customer first name and last name.
SELECT C.CUSTOMER_FIRSTNAME, C.CUSTOMER_LASTNAME, COUNT(T.TRANSACTION_ID)
FROM customer C
INNER JOIN library_card LC ON C.CUSTOMER_ID = LC.CUSTOMER_ID
INNER JOIN transaction T ON LC.LIBRARY_CARD_ID = T.LIBRARY_CARD_ID
INNER JOIN physical_item P ON T.PHYSICAL_ITEM_ID = P.PHYSICAL_ITEM_ID
INNER JOIN catalog_item CT ON P.CATALOG_ITEM_ID = CT.CATALOG_ITEM_ID
GROUP BY C.CUSTOMER_FIRSTNAME, C.CUSTOMER_LASTNAME
ORDER BY C.CUSTOMER_FIRSTNAME, C.CUSTOMER_LASTNAME;
Run first: https://drive.google.com/open?id=1PYAZV4KIfZtxP4eQn35zsczySsxDM7ls
Run second: https://drive.google.com/open?id=1pAzWmJqvD3o3n6YJqVUM6TtxDafKGd3f
EDIT
With some help from Mr. Barbaros I've come up with the below query, which is closer. However, this query isn't returning any results for DVDs, which leads me to believe it's a join issue.
SELECT C.CUSTOMER_FIRSTNAME, C.CUSTOMER_LASTNAME, COUNT(CT1.TYPE) AS BOOK_COUNT, COUNT(CT2.TYPE) AS DVD_COUNT
FROM customer C
INNER JOIN library_card LC ON C.CUSTOMER_ID = LC.CUSTOMER_ID
INNER JOIN transaction T ON LC.LIBRARY_CARD_ID = T.LIBRARY_CARD_ID
INNER JOIN physical_item P ON T.PHYSICAL_ITEM_ID = P.PHYSICAL_ITEM_ID
INNER JOIN catalog_item CT1 ON P.CATALOG_ITEM_ID = CT1.CATALOG_ITEM_ID AND CT1.TYPE = 'BOOK'
LEFT OUTER JOIN catalog_item CT2 ON P.CATALOG_ITEM_ID = CT2.CATALOG_ITEM_ID AND CT2.TYPE = 'DVD'
GROUP BY C.CUSTOMER_FIRSTNAME, C.CUSTOMER_LASTNAME, CT1.TYPE, CT2.TYPE
ORDER BY C.CUSTOMER_FIRSTNAME, C.CUSTOMER_LASTNAME;
Use "conditional aggregates" (use a case expression inside the aggregate function)
SELECT
C.CUSTOMER_FIRSTNAME
, C.CUSTOMER_LASTNAME
, COUNT( CASE WHEN CT.TYPE = 'BOOK' THEN T.TRANSACTION_ID END ) books
, COUNT( CASE WHEN CT.TYPE = 'DVD' THEN T.TRANSACTION_ID END ) dvds
FROM customer C
INNER JOIN library_card LC ON C.CUSTOMER_ID = LC.CUSTOMER_ID
INNER JOIN transaction T ON LC.LIBRARY_CARD_ID = T.LIBRARY_CARD_ID
INNER JOIN physical_item P ON T.PHYSICAL_ITEM_ID = P.PHYSICAL_ITEM_ID
INNER JOIN catalog_item CT ON P.CATALOG_ITEM_ID = CT.CATALOG_ITEM_ID
GROUP BY
C.CUSTOMER_FIRSTNAME
, C.CUSTOMER_LASTNAME
HAVING
COUNT( CASE WHEN CT.TYPE = 'BOOK' THEN T.TRANSACTION_ID END )
> COUNT( CASE WHEN CT.TYPE = 'DVD' THEN T.TRANSACTION_ID END )
ORDER BY
C.CUSTOMER_FIRSTNAME
, C.CUSTOMER_LASTNAME
;
You can use catalog_item table twice( think of as seperate tables for books and dvds ), and compare by HAVING clause as :
SELECT C.CUSTOMER_FIRSTNAME, C.CUSTOMER_LASTNAME,
COUNT(CT1.CATALOG_ITEM_ID) as "Book Checkout",
COUNT(CT2.CATALOG_ITEM_ID) as "DVD Checkout"
FROM customer C
INNER JOIN library_card LC ON C.CUSTOMER_ID = LC.CUSTOMER_ID
INNER JOIN transaction T ON LC.LIBRARY_CARD_ID = T.LIBRARY_CARD_ID
INNER JOIN physical_item P ON T.PHYSICAL_ITEM_ID = P.PHYSICAL_ITEM_ID
LEFT JOIN catalog_item CT1 ON P.CATALOG_ITEM_ID = CT1.CATALOG_ITEM_ID AND CT1.TYPE = 'BOOK'
LEFT JOIN catalog_item CT2 ON P.CATALOG_ITEM_ID = CT2.CATALOG_ITEM_ID AND CT1.TYPE = 'DVD'
GROUP BY C.CUSTOMER_FIRSTNAME, C.CUSTOMER_LASTNAME
HAVING COUNT(CT1.CATALOG_ITEM_ID) > COUNT(CT2.CATALOG_ITEM_ID)
ORDER BY C.CUSTOMER_FIRSTNAME, C.CUSTOMER_LASTNAME;
CUSTOMER_FIRSTNAME CUSTOMER_LASTNAME Book Checkout DVD Checkout
------------------ ----------------- ------------- -------------
Deena Pilgrim 3 1
Emile Cross 5 2
Please try to remove ,CT1.TYPE, CT2.TYPE on your group by clause.

Finding the count

I have the following SQL query and need to know the count of companyid as I can see repeating data. How do I find the count of it. Following is the query
SELECT a.companyId 'companyId'
, i.orgDebtType 'orgDebtType'
, d.ratingTypeName 'ratingTypeName'
, c.currentRatingSymbol 'currentRatingSymbol'
, c.ratingStatusIndicator 'ratingStatusIndicator'
, g.qualifierValue 'qualifierValue'
, c.ratingdate 'ratingDate'
, h.value 'outlook'
FROM ciqRatingEntity a
JOIN ciqcompany com
on com.companyId = a.companyId
JOIN ciqratingobjectdetail b ON a.entitySymbolValue = b.objectSymbolValue
JOIN ciqRatingData c ON b.ratingObjectKey = c.ratingObjectKey
JOIN ciqRatingType d ON b.ratingTypeId = d.ratingTypeId
JOIN ciqRatingOrgDebtType i ON i.orgDebtTypeId=b.orgDebtTypeId
JOIN ciqRatingEntityData red ON red.entitySymbolValue=a.entitySymbolValue
AND red.ratingDataItemId='1' ---CoName
LEFT JOIN ciqRatingDataToQualifier f ON f.ratingDataId = c.ratingDataId
LEFT JOIN ciqRatingQualifiervalueType g ON g.qualifiervalueid = f.qualifierValueId
LEFT JOIN ciqRatingValueType h ON h.ratingValueId = c.outlookValueId
WHERE 1=1
AND b.ratingTypeId IN ( '130', '131', '126', '254' )
-- and a.companyId = #companyId
AND a.companyId IN
(SELECT distinct TOP 2000000
c.companyId
FROM ciqCompany c
inner join ciqCompanyStatusType cst on cst.companystatustypeid = c.companystatustypeid
inner join ciqCompanyType ct on ct.companyTypeId = c.companyTypeId
inner join refReportingTemplateType rep on rep.templateTypeId = c.reportingtemplateTypeId
inner join refCountryGeo rcg on c.countryId = rcg.countryId
inner join refState rs on rs.stateId = c.stateId
inner join ciqSimpleIndustry sc on sc.simpleIndustryId = c.simpleIndustryId
ORDER BY companyid desc)
ORDER BY companyId DESC, c.ratingdate, b.ratingTypeId, c.ratingStatusIndicator
This will list where there are duplicate companyID's
SELECT companyId, count(*) as Recs
FROM ciqCompany
GROUP BY ciqCompany
HAVING count(*) > 1
I understand that you wish to add a column to the query with the count of each companyId, you can use COUNT() OVER():
select count(a.companyId) over (partition by a.companyId) as companyCount,
<rest of the columns>
from ciqRatingEntity a
join <rest of the query>
This would return in each row the count of the companyId of that row without grouping the results.

how to optimized without union clauses?

Is it possible to write below query without a union clause.
select ProductId,ImageName,ImageType, ROW_NUMBER() over (order by ProductId desc) RowId
from
(
select p.id ProductId ,p.pic_image ImageName,'pic_image' ImageType
from product p
left outer join iimages_edited pe on p.id = pe.[id]
where isnull(p.pic_image,'') <> '' and isnull(pe.pic_image,0)=0
union
select p.id ProductId,p.pic_bimage ImageName,'pic_bimage' ImageType
from product p
left outer join iimages_edited pe on p.id = pe.[id]
where isnull(p.pic_bimage,'') <> '' and isnull(pe.pic_bimage,0)=0
union
select p.id ProductId,p.pic_limage ImageName,'pic_limage' ImageType
from product p
left outer join iimages_edited pe on p.id = pe.[id]
where isnull(p.pic_limage,'') <> '' and isnull(pe.pic_limage,0)=0
union
select p.id ProductId,p.pic_blimage ImageName,'pic_blimage' ImageType
from product p
left outer join iimages_edited pe on p.id = pe.[id]
where isnull(p.pic_blimage,'') <> '' and isnull(pe.pic_blimage,0)=0
union
select p.id ProductId,p.pic_cimage ImageName,'pic_cimage' ImageType
from product p
left outer join iimages_edited pe on p.id = pe.[id]
where isnull(p.pic_cimage,'') <> '' and isnull(pe.pic_cimage,0)=0
)t
Above query has same table but different where condition, It is
possible to do it in a single query ?
Any help will be much appreciated !
Thanks in advance
It seems that you are repeating the same join and filters with differents columns each time. You can convert them to rows using UNPIVOT, on each table, before the join :
select pe.ProductId, p.ProductId, p.ImageName, p.ImageType, ROW_NUMBER()
over (order by p.ProductId desc) RowId
from (
select id as ProductId, ImageType, ImageName
from product
unpivot (
ImageType for ImageName
in (pic_image, pic_bimage, pic_limage, pic_blimage, pic_cimage)
) t
) as p
left outer join (
select id as ProductId, ImageType, ImageName
from iimages_edited
unpivot (
ImageType for ImageName
in (pic_image, pic_bimage, pic_limage, pic_blimage, pic_cimage)
) t
) as pe
on p.ImageType = pe.ImageType
and p.ProductId = pe.ProductId
where pe.ProductId is null
UNPIVOT filters null values, so ISNULL are probably not necessary.

Calculating stock quantity from multiple table transactions with SQL

We had an issue with our stock whereby we had a balance column that would be added to or subtracted from whenever a transaction occurred.
There were some issues that we could not trace and hence have made changes whereby the stock would be calculated by adding and subtracting (where appropriate) the quantity moving and come up to today's stock value.
However now, the structure is such that one product has multiple stocks therefore product A with expiry 01/2012, 02/2013 etc.
I have currently created a query whereby for one stock of a product, it would calculate its current stock as follows:
select
(select ISNULL(sum(gd.qty),0) as grnadd from grns as g
INNER JOIN grndetails as gd ON g.id = gd.grnid
INNER JOIN stocks as s ON s.id = gd.stockid
where g.locationid = 10 and s.prodid =2653)
-
(select ISNULL(sum(cod.qty), 0) as salesub from salesorders as co
INNER JOIN salesorddetails as cod ON co.id = cod.cusordid
INNER JOIN stocks as s ON s.id = cod.stockid
where co.status != 'cancel' and co.locid = 10 and s.prodid =2653)
-
(select ISNULL(sum(cod.qty), 0) as cussub from customerorders as co
INNER JOIN customerorddetails as cod ON co.id = cod.cusordid
INNER JOIN stocks as s ON s.id = cod.stockid
where co.status != 'cancel' and co.locid = 10 and s.prodid =2653)
Therefore in this case the stock is calculated for one product however can I make a query that would list all products with their totals (as above) in the second column?
Thank you and hope the structure is understood from the above query
EDIT:
Stocks Table: id, prodid, expiry
Products Table: id, tradename
GRN Details Table: id, grnid, qty, stockid (since its affecting the stock not product)
Sales & Customer Order Details Table: id, cusordid, qty, stockid
GRN & Sales & Cus Ord Table: id, locid
Locations Table: id, locname
try to include all product-ids and group by it. here's some proposed code
select prodid, sum(total) as total from (
(select s.prodid
, ISNULL(sum(gd.qty),0) as total
from grns as g
INNER JOIN grndetails as gd
ON g.id = gd.grnid
INNER JOIN stocks as s
ON s.id = gd.stockid
where g.locationid = 10 group by s.prodid)
union all
(select s.prodid
, ISNULL(sum(cod.qty), 0)*(-1) as total
from salesorders as co
INNER JOIN salesorddetails as cod
ON co.id = cod.cusordid
INNER JOIN stocks as s
ON s.id = cod.stockid
where co.status != 'cancel'
and co.locid = 10 group by s.prodid)
union all
(select s.prod_id
, ISNULL(sum(cod.qty), 0)*(-1) as total
from customerorders as co
INNER JOIN customerorddetails as cod
ON co.id = cod.cusordid
INNER JOIN stocks as s
ON s.id = cod.stockid
where co.status != 'cancel'
and co.locid = 10 group by s.prodid)
) as x
group by prodid
i have changed all the minuses to union-alls so that the product-ids will not get subtracted from each other and the grand total will be calculated respective to your product-ids.
Try this:
WITH
S AS (
SELECT DISTINCT prodid FROM stocks
),
L AS (
/* SELECT 10 AS locationid */
SELECT DISTINCT locationid FROM grns
),
T1 AS (
select
g.locationid,
s.prodid,
sum(gd.qty) as grnadd
from grns as g
INNER JOIN grndetails as gd ON g.id = gd.grnid
INNER JOIN stocks as s ON s.id = gd.stockid
GROUP BY g.locationid, s.prodid
),
T2 AS (
select
co.locid as locationid,
s.prodid,
sum(cod.qty) as salesub
from salesorders as co
INNER JOIN salesorddetails as cod ON co.id = cod.cusordid
INNER JOIN stocks as s ON s.id = cod.stockid
where co.status != 'cancel'
GROUP BY co.locid, s.prodid
),
T3 AS (
select
co.locid as locationid,
s.prodid,
sum(cod.qty) as cussub
from customerorders as co
INNER JOIN customerorddetails as cod ON co.id = cod.cusordid
INNER JOIN stocks as s ON s.id = cod.stockid
where co.status != 'cancel'
GROUP BY co.locid, s.prodid
)
SELECT
S.prodid, L.locationid, ISNULL(grnadd, 0) - ISNULL(salesub, 0) - ISNULL(cussub, 0)
FROM
S CROSS JOIN
L LEFT OUTER JOIN
T1 ON T1.locationid = L.locationid AND T1.prodid = S.prodid LEFT OUTER JOIN
T2 ON T2.locationid = L.locationid AND T2.prodid = S.prodid LEFT OUTER JOIN
T3 ON T3.locationid = L.locationid AND T3.prodid = S.prodid
I assumed that location might be also important, so it returns 3 columns. If you want results only for location with id 10, then in L CTL uncomment first line and comment second.
assuming lots about your data model (hopefully i understood the question right), a group by might be the answer:
select
(select s.prodid, ISNULL(sum(gd.qty),0) as grnadd from grns as g
INNER JOIN grndetails as gd ON g.id = gd.grnid
INNER JOIN stocks as s ON s.id = gd.stockid
where g.locationid = 10
GROUP BY s.prodid)
-
(select s.prodid, ISNULL(sum(cod.qty), 0) as salesub from salesorders as co
INNER JOIN salesorddetails as cod ON co.id = cod.cusordid
INNER JOIN stocks as s ON s.id = cod.stockid
where co.status != 'cancel' and co.locid = 10
GROUP BY s.prodid)
-
(select s.prodid, ISNULL(sum(cod.qty), 0) as cussub from customerorders as co
INNER JOIN customerorddetails as cod ON co.id = cod.cusordid
INNER JOIN stocks as s ON s.id = cod.stockid
where co.status != 'cancel' and co.locid = 10
GROUP BY s.prodid)

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