order sql query by name - sql

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

Related

Best way to get a count of each category type

I have a query below which returns the product_id, product_name and category_name from two different tables.
SELECT p.product_id,
p.product_name,
c.category_name
FROM [BikeStore].[production].[products] p
JOIN [BikeStore].[production].[categories] c
ON p.category_id = c.category_id
ORDER BY c.category_name
I want to add a fourth column next to each row showing how many of each categories are there.
I wrote the query for this like this below:
SELECT p.product_id,
p.product_name,
c.category_name,
(SELECT Count(*)
FROM [BikeStore].[production].[products] p1
JOIN [BikeStore].[production].[categories] c1
ON p1.category_id = c1.category_id
WHERE c1.category_id = c.category_id) AS totals
FROM [BikeStore].[production].[products] p
JOIN [BikeStore].[production].[categories] c
ON p.category_id = c.category_id
ORDER BY c.category_name
I am not sure if this is the right approach. Could you please let me know if there is a better way to do this.
You can use a window function:
SELECT p.product_id,
p.product_name,
c.category_name,
COUNT(*) OVER (PARTITION BY c.category_name)
FROM [BikeStore].[production].[products] p JOIN
[BikeStore].[production].[categories] c
ON p.category_id = c.category_id
ORDER BY c.category_name

SQL SERVER , error in my query

I need to know where is the problem in query, and how can I solve this?
SQL Query :
SELECT
P.NameAr, P.NameEn,
Sum(p.OrderQty) AS SumQty ,
Sum(p.OrderQty * P.NewPrice) AS SumQtyPrice ,
ROW_NUMBER() OVER(ORDER BY D.ProductID ASC) AS Number,
'Soon' AS ColSoon
FROM OrderMasters M
INNER JOIN OrderDetails D ON D.OrderMasterID = M.OrderMasterID
INNER JOIN Products P ON P.ProductID = D.ProductID
INNER JOIN Categories C ON C.CategoryID = P.CategoryID
GROUP BY P.NameAr, P.NameEn
Order By D.OrderDetailsID
Error Msg :
Msg 8120, Level 16, State 1, Line 7
Column 'OrderDetails.ProductID' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
When I remove line consisting #RowNumber code execute with no problem, but I need that in query.
You can't apply order by field which doesn't belongs to group by;
So, you should change it your order by clauses
SELECT
P.NameAr, P.NameEn,
Sum(p.OrderQty) AS SumQty ,
Sum(p.OrderQty * P.NewPrice) AS SumQtyPrice ,
ROW_NUMBER() OVER(ORDER BY P.NameAr ASC) AS Number,
'Soon' AS ColSoon
FROM OrderMasters M
INNER JOIN OrderDetails D ON D.OrderMasterID = M.OrderMasterID
INNER JOIN Products P ON P.ProductID = D.ProductID
INNER JOIN Categories C ON C.CategoryID = P.CategoryID
GROUP BY P.NameAr, P.NameEn
Order By P.NameAr
I put the P.NameAr as order field to provide example.
SELECT
P.NameAr, P.NameEn,
Sum(p.OrderQty) AS SumQty ,
Sum(p.OrderQty * P.NewPrice) AS SumQtyPrice ,
ROW_NUMBER() OVER(ORDER BY D.ProductID ASC) AS Number,
'Soon' AS ColSoon,
D.OrderDetailsID
FROM OrderMasters M
INNER JOIN OrderDetails D ON D.OrderMasterID = M.OrderMasterID
INNER JOIN Products P ON P.ProductID = D.ProductID
INNER JOIN Categories C ON C.CategoryID = P.CategoryID
GROUP BY P.NameAr, P.NameEn,D.ProductID,D.OrderDetailsID
Order By D.OrderDetailsID
I'm solve this thx all for hints
GROUP BY should contain D.PRODUCTID as well:
group by p.NameAr, p.NameEn, d.ProductID

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

AVG of AVG, aggregate functions of subquery

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

Manipulating Data in Joins

Diagram:
Query for join:
SELECT DISTINCT c.CustomerID, c.FirstName , sh.DueDate, p.ProductID,p.ListPrice
FROM SalesLT.Customer c
INNER JOIN SalesLT.SalesOrderHeader sh
ON c.CustomerID = sh.CustomerID
INNER JOIN SalesLT.SalesOrderDetail sd
ON sh.SalesOrderID = sd.SalesOrderID
INNER JOIN SalesLT.Product p
ON sd.ProductID = p.ProductID
Order BY ListPrice Desc
Output:
Desired Result:
For desired output:
What could be the add on to the existing query?
What would be the optimized way of doing this query ?
What would be the time and space complexity for Sub query and join?
I think you want:
SELECT c.CustomerID
, c.FirstName
, sh.DueDate
, MAX(p.ProductID) ProductID
,p.ListPrice
FROM SalesLT.Customer c
INNER JOIN SalesLT.SalesOrderHeader sh
ON c.CustomerID = sh.CustomerID
INNER JOIN SalesLT.SalesOrderDetail sd
ON sh.SalesOrderID = sd.SalesOrderID
INNER JOIN SalesLT.Product p
ON sd.ProductID = p.ProductID
GROUP BY
, c.FirstName
, sh.DueDate
, p.ListPrice
Order BY ListPrice Desc
Not that it makes much sense as a query, but I guess you wanted to know the approach? Probably you have a good answer by now, but it encourages us to put time into an answer if you tick an appropriate response, thanks