SQL SERVER , error in my query - sql

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

Related

How to add TOP 1 in query with left join in views?

I have 3 same product in ID=42, with 3 different images. I want to take the first image from the product ID, I try adding "TOP 1", error
This is my query
CREATE OR REPLACE VIEW UserOrdersView
AS
SELECT
u.[User_ID],
p.Product_Name,
p.Price,
o.Order_Price,
o.Order_ID,
i.[Image]
FROM Product p
LEFT JOIN Orders o ON o.Product_ID = p.Product_ID
INNER JOIN Users u ON u.[User_ID]= o.[User_ID]
LEFT JOIN Product_Images i ON i.Product_ID = p.Product_ID
WHERE o.[User_ID] = 42
You need to use OUTER APPLY to get top 1 image data from Product_image table based on Product ID.
Please check this Real life example, when to use OUTER / CROSS APPLY in SQL stackoverflow link for more knowledge.
Please check below updated view code for your answer.
CREATE OR REPLACE VIEW UserOrdersView
AS
BEGIN
SELECT
u.[User_ID],
p.Product_Name,
p.Price,
o.Order_Price,
o.Order_ID,
i.[Image]
FROM Product p
INNER JOIN Users u ON u.[User_ID]= o.[User_ID]
LEFT JOIN Orders o ON o.Product_ID = p.Product_ID
OUTER APPLY
(
SELECT TOP 1
T2.[Image]
FROM Product_Images T2
WHERE T2.Product_ID = p.Product_ID
) i
WHERE o.[User_ID] = 42
END
GO
WITH cte as (
SELECT
u.[User_ID],
p.Product_Name,
p.Price,
o.Order_Price,
o.Order_ID,
i.[Image],
ROW_NUMBER() OVER (PARTITION BY i.[Image] ORDER BY p.Product_Name) AS rn
FROM Product p
LEFT JOIN Orders o ON o.Product_ID = p.Product_ID
INNER JOIN Users u ON u.[User_ID]= o.[User_ID]
LEFT JOIN Product_Images i ON i.Product_ID = p.Product_ID
)
SELECT [User_ID],Product_Name,Price,Order_Price,Order_ID,[Image] FROM cte
WHERE rn=1
Put your all query inside a CTE with a new column that you will use to filter the results.
This new column is produced with ROW_NUMBER() function partitioned by Product_Name

Selecting the Id of the item with a MAX value when doing a left join

Each product in the database can have many revisions. Some products might not have any revisions at all.
ProductRevision table has the following fields: Id, Version, SubmitDate
I am trying to figure out how I can select a field called LatestRevisionId based on the MAX SubmitDate and if not revision then the field will be null
SELECT p.Id, p.Name, p.Price
FROM Product p
LEFT OUTER JOIN ProductRevision pr ON p.Id = pr.ProductId
Do I have to do a sub select in my select? I really want to try and use HAVING but can't figure out how to do it with a left join.
I was trying to do the following as a sub select:
(SELECT Id
FROM ProductRevision
WHERE ProductId=p.Id
HAVING SubmitDate=MAX(SubmitDate)
) AS LatestVersionId
Please note that I am using SQL SERVER 2008
Here's one option using row_number:
SELECT *
FROM (
SELECT p.Id, p.Name, p.Price, pr.id as LatestRevisionId,
row_number() over (partition by p.Id order by pr.SubmitDate desc) rn
FROM Product p
LEFT OUTER JOIN ProductRevision pr PN p.Id = pr.ProductId
) t
WHERE rn = 1
This will select a single Product with the latest matching row from the ProductRevision table.
If you just prefer to use max, then you need to join the table back to itself again:
SELECT p.Id, p.Name, p.Price, pr.id as LatestRevisionId
FROM Product p
LEFT OUTER JOIN ProductRevision pr PN p.Id = pr.ProductId
LEFT OUTER JOIN (SELECT ProductId, MAX(SubmitDate) MaxSubmitDate
FROM ProductRevision
GROUP BY ProductId) mpr ON pr.ProductId = mpr.ProductId AND
pr.SubmitDate = mpr.MaxSubmitDate
This could perhaps return duplicates though if multiple revisions share the same date.
if you are using SQL Server 2012 and aboe, below code will give you desired result.
SELECT DISTINCT p.Id, p.Name, p.Price, FIRST_VALUE(pr.ID) OVER (PARTITION BY p.Id ORDER BY pr.SubmitDate DESC) AS LatestVersionId
FROM Product p
LEFT OUTER JOIN ProductRevision pr ON p.Id = pr.ProductId
You can use a LEFT JOIN like this:
SELECT p.Id, p.Name, p.Price, pr.RevisionId as LatestRevisionId
FROM Product p LEFT OUTER JOIN
(SELECT pr.*,
ROW_NUMBER() OVER (PARTITION BY ProductId ORDER BY SubmitDate DESC) as seqnum
FROM ProductRevision pr
)
ON p.Id = pr.ProductId AND seqnum = 1;
If you want to aggregation other values, then just do:
SELECT p.Id, p.Name, p.Price,
MAX(CASE WHEN seqnum = 1 THEN pr.RevisionId END) as LatestRevisionId
FROM Product p LEFT OUTER JOIN
(SELECT pr.*,
ROW_NUMBER() OVER (PARTITION BY ProductId ORDER BY SubmitDate DESC) as seqnum
FROM ProductRevision pr
)
ON p.Id = pr.ProductId
GROUP BY p.Id, p.Name, p.Price;
This should be the simplest method to accomplish what you want.

SQL Select query for Select 3 different products

Good Evening,
I've been struggling with a select query on my database on which I want to determine the clients that have placed an order of 3 products from at least 3 different product categories.
Then I want to print the CustomerID and the number of the orders.
This is my Database diagram:
Any Answer would be helpful,
Sincerely Thanos.
I haven't tested this, but I believe it should be close to correct:
SELECT h.CustomerID, COUNT(DISTINCT h.SalesOrderID)
FROM SalesOrderHeader h
INNER JOIN SalesOrderDetail d1 ON h.SalesOrderID = d1.SalesOrderID
INNER JOIN SalesOrderDetail d2 ON h.SalesOrderID = d2.SalesOrderID
INNER JOIN SalesOrderDetail d3 ON h.SalesOrderID = d3.SalesOrderID
INNER JOIN Product p1 ON d1.ProductID = p1.ProductID
INNER JOIN Product p2 ON d2.ProductID = p2.ProductID
INNER JOIN Product p3 ON d3.ProductID = p3.ProductID
WHERE p1.ProductCategoryID <> p2.ProductCategoryID
AND p2.ProductCategoryID <> p3.ProductCategoryID
AND p1.ProductCategoryID <> p3.ProductCategoryID
GROUP BY h.CustomerID
select CustomerId, count(*)
from(
select CustomerId
from SalesOrderHeader soh
join SalesOrderDetail sod using (SalesOrderID)
join Product p using (ProductId)
group by CustomerId, SalesOrderId
having count(distinct ProductCategoryID) > 2
) a
group by CustomerId
I think this should get you the result
Select CustomerID,SalesOrderID , count(CategoryID) CatCount
From
SalesOrderHeader Head inner join SalesOrderDetail Det
on Head.SalesOrderID = Det.SalesOrderID
inner join Product Prod
on Prod.ProductID = Det.ProductID
inner join ProductCategory PCat
on Prod.CategoryID = PCat.CategoryID
Group By CustomerID,SalesOrderID
Having count(CategoryID) > 3
like for : "Can't solve this SQL query"
select CustomerID,count(*) as amount_of_order from
SalesOrder join
(
select SalesOrderID,count(distinct ProductCategoryID) CategoryCount
from SalesOrderDetail JOIN Product using (ProductId)
group by 1
) CatCount using (SalesOrderId)
group by 1
having bool_or(CategoryCount>=3) -- At least on CategoryCount>=3

Missing Right Parenthesis issue

This is the Query I have written
Select C.CUST_NAME,P.PROD_DESCRIP from Customer C
JOIN (Ord O,OrderItem OT, Product P) ON (C.CUST_ID = O.CUST_ID AND O.ORD_ID = OT.ORD_ID AND OT.PROD_ID = P.PROD_ID) GROUP BY C.CUST_NAME ORDER BY OT.ORDITEM_QTY DESC
But the issue is it giving me Right Parenthesis Missing issue
Although that join syntax is allowed in some databases, it is really much clearer to split out the joins:
Select C.CUST_NAME, P.PROD_DESCRIP
from Customer C JOIN
Ord O
on C.CUST_ID = O.CUST_ID JOIN
OrderItem OT
on O.ORD_ID = OT.ORD_ID JOIN
Product P
ON OT.PROD_ID = P.PROD_ID
GROUP BY C.CUST_NAME
ORDER BY OT.ORDITEM_QTY DESC;
By the way, this probably isn't doing what you think it does. It is returning a customer name along with an arbitrary prod_descrip. It is then ordering this result by an arbitrary quantity -- perhaps from the same or a different row.
If you want to get the customer name along with the product with the maximum quantity for that customer, you can do this:
Select C.CUST_NAME,
substring_index(group_concat(P.PROD_DESCRIP order by OT.ORDITEM_QTY desc), ',', 1) as PROD_DESCRIP
from Customer C JOIN
Ord O
on C.CUST_ID = O.CUST_ID JOIN
OrderItem OT
on O.ORD_ID = OT.ORD_ID JOIN
Product P
ON OT.PROD_ID = P.PROD_ID
GROUP BY C.CUST_NAME;
Note: If PROD_DESCRIP could have a comma then you will want to use a different separator character.
EDIT:
The above is the MySQL solution. In Oracle, you would do:
select CUST_NAME, PROD_DESCRIP
from (Select C.CUST_NAME, P.PROD_DESCRIP,
row_number() over (partition by C.CUST_NAME order by OT.ORDITEM_QTY desc) as seqnum
from Customer C JOIN
Ord O
on C.CUST_ID = O.CUST_ID JOIN
OrderItem OT
on O.ORD_ID = OT.ORD_ID JOIN
Product P
ON OT.PROD_ID = P.PROD_ID
) t
where seqnum = 1;
This is actually the preferred standard SQL solution. It will work in most databases (SQL Server, Oracle, Postgres, DB2, and Teradata).
SELECT C.CUST_NAME, P.PROD_DESCRIP
FROM Customer C
INNER JOIN Ord O ON C.CUST_ID = O.CUST_ID
INNER JOIN OrderItem OT ON O.ORD_ID = OT.ORD_ID
INNER JOIN Product P ON OT.PROD_ID = P.PROD_ID
GROUP BY C.CUST_NAME
ORDER BY OT.ORDITEM_QTY DESC
SELECT C.CUST_NAME,P.PROD_DESCRIP
FROM Customer C
JOIN Ord O
ON C.CUST_ID = O.CUST_ID
JOIN OrderItem OT
ON O.ORD_ID = OT.ORD_ID
JOIN Product P
ON OT.PROD_ID = P.PROD_ID
GROUP BY C.CUST_NAME
ORDER BY OT.ORDITEM_QTY DESC

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