AVG of AVG, aggregate functions of subquery - sql

This subquery produces the correct table. But now I want to get the average of the averages, and I'm getting an error "Missing FROM-clause entry for table "c"".
SELECT
c.name,
AVG(avgvalue)
FROM
(
SELECT
c.name,
p.name,
AVG(a."value") AS avgvalue
FROM answers a INNER JOIN survey_responses sr ON sr.id = a.survey_response_id AND a.question_id = 13
INNER JOIN answers category_answer ON category_answer.survey_response_id = sr.id AND category_answer.question_id = 264
INNER JOIN answers_categories ac ON category_answer.id = ac.answer_id
INNER JOIN categories c ON c.id = ac.category_id
INNER JOIN products p ON p.id = a.product_id
WHERE c.name IN ('Accounting')
GROUP BY c.name, p."name"
HAVING count(p.name)>10
) as ProductAverages
GROUP BY c.name;

You are naming the ProductAverages, so your table aliases should reference it, not c - which can be used only in the inner query:
SELECT
name, -- Here
AVG(avgvalue)
FROM
(
SELECT
c.name,
p.name,
AVG(a."value") AS avgvalue
FROM answers a INNER JOIN survey_responses sr ON sr.id = a.survey_response_id AND a.question_id = 13
INNER JOIN answers category_answer ON category_answer.survey_response_id = sr.id AND category_answer.question_id = 264
INNER JOIN answers_categories ac ON category_answer.id = ac.answer_id
INNER JOIN categories c ON c.id = ac.category_id
INNER JOIN products p ON p.id = a.product_id
WHERE c.name IN ('Accounting')
GROUP BY c.name, p."name"
HAVING count(p.name)>10
) as ProductAverages
GROUP BY name; -- and here

Related

How connect two select?

I have a problem with select from two table.
I use filtr from date, when I used NOT IN but didn't work, because data to result not in second table. I want display outfits which is free in these date and outfits which not in table rent.
Structure of base in the picture:
SELECT o.Id, o.Name, c.Name, o.Description,o.Price, r.Date1, r.Date2, r.Return
FROM Outfit o INNER JOIN
Category c
ON o.Category = c.Id INNER JOIN
Rent r
ON o.Id = r.OutFit
WHERE (myfiltrdate NOT BETWEEN r.Date1 AND r.Date2) OR
r.Return IS NOT NULL
Now my result are only record/outfit which are Rent table, but I want this result and Outfit which are not in table Rent
You may try a left join -
SELECT o.Id, o.Name, c.Name, o.Description,o.Price, r.Date1, r.Date2, r.Return
FROM Outfit o LEFT JOIN
Category c
ON o.Category = c.Id INNER JOIN
Rent r
ON o.Id = r.OutFit
WHERE (myfiltrdate NOT BETWEEN r.Date1 AND r.Date2) OR
r.Return IS NULL
I think you want LEFT JOINs and filtering. Something like this:
SELECT o.Id, o.Name, c.Name, o.Description, o.Price,
r.Date1, r.Date2, r.Return
FROM Outfit o LEFT JOIN
Category c
ON o.Category = c.Id LEFT JOIN
Rent r
ON o.Id = r.OutFit AND
(myfiltrdate BETWEEN r.Date1 AND r.Date2)
WHERE r.Return IS NULL;
Change your query to left join and filter the dates like this:
SELECT o.Id, o.Name, c.Name, o.Description,o.Price, r.Date1, r.Date2, r.Return
FROM Outfit o
INNER JOIN Category c ON o.Category = c.Id
LEFT JOIN Rent r ON o.Id = r.OutFit
WHERE (myfiltrdate < r.Date1 AND myfiltrdate > r.Date2) OR
r.Return IS NOT NULL
I don't have clear if Return is a date which the outfit is returned or is a boolean but I suspect that the condition must be
And r.Return IS NOT NULL

SQL join subquery where condition

How can I effectively subquery a LEFT OUTER JOIN so that only rows that meet a specific condition in the join are included?
I'd like to only count PPPD's where converted_at IS NULL. However when I add PPPD.converted_at IS NULL, then the result is more limited than I'd like it to be because it only includes patient_profiles that do have a row with null in converted_at. Instead I'd like a count of all PPPD records that have converted_at = null
SELECT P.id, P.gender, P.dob,
count(distinct recommendations.id) AS recommendation_count,
count(distinct PPPD.id) AS community_submissions,
FROM patient_profiles AS P
LEFT OUTER JOIN recommendations ON recommendations.patient_profile_id = P.id
LEFT OUTER JOIN patient_profile_potential_doctors AS PPPD ON PPPD.patient_profile_id = P.id
WHERE P.is_test = FALSE
GROUP BY P.id
You need to add the condition in the ON clause:
SELECT P.id, P.gender, P.dob,
count(distinct r.id) AS recommendation_count,
count(distinct PPPD.id) AS community_submissions,
FROM patient_profiles P LEFT OUTER JOIN
recommendations r
ON r.patient_profile_id = P.id LEFT OUTER JOIN
patient_profile_potential_doctors PPPD
ON PPPD.patient_profile_id = P.id AND PPPD.converted_at IS NULL
WHERE P.is_test = FALSE;
GROUP BY P.id

Left outer join with only first row

I have a query something like
SELECT S.product_id, S.link, C.id AS category_id
FROM Products P
INNER JOIN SEO S ON S.product_id = P.id AND P.product_type = 1
LEFT OUTER JOIN Categories C ON c.product_id = P.id
WHERE P.active = 1
I works fine for me as long as each product has assigned to only one category. But if a product is assigned to many categories it returns all possible combinations.
Can I only select the first one and if a product don't have any category the link should still be returned with category_id = NULL
An easy way is to use outer apply, so as to have a correlated join, and make that a top 1 query. Thus you are able to access all columns of the category record in question. I'm adding a category name here as an example:
select s.product_id, s.link, c.id as category_id, c.name as category_name
from products p
inner join seo s on s.product_id = p.id
outer apply
(
select top 1 *
from categories cat
where cat.product_id = p.id
order by cat.id
) c
where p.active = 1
and p.product_type = 1;
You can use a GROUP BY to accomplish this along with an Aggregate function, most likely MIN or MAX.
Depending on which Category Id you prefer in your result you could select the minimum.
SELECT S.product_id, S.link, MIN(C.id) AS category_id
FROM Products P
INNER JOIN SEO S ON S.product_id = P.id AND P.product_type = 1
LEFT OUTER JOIN Categories C ON c.product_id = P.id
WHERE P.active = 1
GROUP BY S.product_id, S.link
Or the maximum.
SELECT S.product_id, S.link, MAX(C.id) AS category_id
FROM Products P
INNER JOIN SEO S ON S.product_id = P.id AND P.product_type = 1
LEFT OUTER JOIN Categories C ON c.product_id = P.id
WHERE P.active = 1
GROUP BY S.product_id, S.link
Alternate solution using subquery:
SELECT S.product_id, S.link,
(
SELECT C.id FROM Categories C WHERE C.product_id = P.id AND
ROW_NUMBER() OVER(ORDER BY /* your sort option goes here*/ ) = 1
) AS category_id
FROM Products P
INNER JOIN SEO S ON S.product_id = P.id AND P.product_type = 1
WHERE P.active = 1

Query , joining, SQL server example (Concert) with a couple of related tables

I dont know who to return what I wrote before, apologise. vowejin firnefk rneqkln qrecjinrelqkjnr klwencirowejncienfvenciernicnreinc ikrenicernircniwncikwnkwjnkcjwnkjnckjncwkjnwckjnweknckejnckwjnckjnwekcjnwekjnckwjenckjwenkcjnwekjnckwenckwjenklwneocnwocnowencoejnkjwencojnwekojcnwekjcnkwejnckejcnkwejnckjwenkcjnwkjcnwkn:)
Using TOP:
SELECT TOP 1
PID, NAME, AGE
FROM (
SELECT
p.*, h.HID
FROM Performer p
INNER JOIN Concert c
ON c.PID = p.PID
INNER JOIN Hall h
ON h.HID = c.HID
INNER JOIN Tickets t
ON t.CID = c.CID
GROUP BY p.PID, p.NAME, p.AGE, h.HID, h.CAPACITY
HAVING COUNT(t.TID) = h.CAPACITY
) t
GROUP BY PID, NAME, AGE
ORDER BY COUNT(*) DESC
This should return expected result
;with Cte1 AS (
select C.CID, P.Name AS PerformerName, H.Name AS HallName, H.Capacity, H.HID
from #Performer P
inner join #Concert C on C.PID = P.PID
inner join #Hall H on H.HID = C.HID
)
, Cte2 AS (
select C.CID, H.HID, COUNT(*) SellCount
from #Concert C
inner join #Hall H on H.HID = C.HID
inner join #Tickets T on T.CID = C.CID
group by C.CID, H.HID
)
select Cte1.CID, Cte1.PerformerName, Cte1.HallName, Cte2.SellCount
from Cte1 inner join Cte2 on Cte2.CID = Cte1.CID AND Cte2.HID = Cte1.HID
where Cte1.Capacity = Cte2.SellCount

order sql query by name

I have a query which I would like to tweak little bit to display different info.
Currently my query gets all the orders with products ranked by the one with most conversions at the top.
Here is the query:
SELECT nopv.ProductVariantID, COUNT(nopv.ProductVariantID), p.ProductId, c.CategoryID, c.Name FROM Nop_OrderProductVariant nopv
INNER JOIN Nop_ProductVariant npv
ON nopv.ProductVariantID = npv.ProductVariantId
INNER JOIN Nop_Product p
ON npv.ProductID = p.ProductId
INNER JOIN Nop_Product_Category_Mapping npcm
ON p.ProductId = npcm.ProductID
INNER JOIN Nop_Category c
ON npcm.CategoryID = c.CategoryID
GROUP BY nopv.ProductVariantID, p.ProductId, c.CategoryID, c.Name
HAVING COUNT(*) > 0
ORDER BY COUNT(nopv.ProductVariantID) DESC
What I have as a result is:
I want to be able to have each category only one time, for example "programmers & modules" category should only one record, containing the sum of all the productvariantIDs in that category. The first field can be avoided as well, because if there are multiple productvariants, the query will need to show just one. What I really need is the count of each category and the categoryID.
Thanks in advance, Laziale
Simply remove the Variant and ProductID from both the select and Group By.
SELECT
COUNT(nopv.ProductVariantID) ,
c.CategoryID ,
c.Name
FROM
Nop_OrderProductVariant nopv
INNER JOIN Nop_ProductVariant npv
ON
nopv.ProductVariantID = npv.ProductVariantId
INNER JOIN Nop_Product p
ON
npv.ProductID = p.ProductId
INNER JOIN Nop_Product_Category_Mapping npcm
ON
p.ProductId = npcm.ProductID
INNER JOIN Nop_Category c
ON
npcm.CategoryID = c.CategoryID
GROUP BY
c.CategoryID ,
c.Name
HAVING
COUNT(*) > 0
ORDER BY
COUNT(nopv.ProductVariantID) DESC
I think the issue is your group by:
GROUP BY nopv.ProductVariantID, p.ProductId, c.CategoryID, c.Name
Try:
GROUP BY c.CategoryID, c.Name -- c.Name is here since you probably can't select it otherwise
Then make whatever changes you need to your SELECT so it will work.
So something like this:
SELECT COUNT(nopv.ProductVariantID), c.CategoryID, c.Name
FROM Nop_OrderProductVariant nopv
INNER JOIN Nop_ProductVariant npv
ON nopv.ProductVariantID = npv.ProductVariantId
INNER JOIN Nop_Product p
ON npv.ProductID = p.ProductId
INNER JOIN Nop_Product_Category_Mapping npcm
ON p.ProductId = npcm.ProductID
INNER JOIN Nop_Category c
ON npcm.CategoryID = c.CategoryID
GROUP BY c.CategoryID, c.Name
HAVING COUNT(*) > 0
ORDER BY COUNT(nopv.ProductVariantID) DESC