I would like to retrieve one large table of products with the latest rows from all the joined tables via with MAX(ID) of each group (productToken) which ich unique name of the product. Joined tables are - products (store), availability (status), description (products), and price of the product. All of them contains the unique productToken and the mentioned tables can be changed over time by adding a new record (independently) so my aim is to compose one big table (with actual info about the products) via retrieving the lastest record from each table. My code is this. First added product worked well, but things got strange after adding new records to any of the tables (query has retrieved no results).
SELECT *
FROM products
JOIN productsStore ON products.productToken = productStore.productToken
JOIN productsStatus ON products.productToken = productsStatus.productToken
JOIN productsPrice ON products.produstToken = productsPrice.productToken
JOIN categories ON products.categoryToken = categories.categoryToken
WHERE products.shopToken = '$shopToken'
AND products.productID IN
(SELECT MAX(productID)
FROM products
GROUP BY productToken)
AND productsPrice.productPriceID IN
(SELECT MAX(productPriceID)
FROM productsPrice
GROUP BY produktToken)
AND productsStatus.productStatusID IN
(SELECT MAX(productStatusID)
FROM productsStatus
GROUP BY productToken)
AND produktyStore.productStoreID IN
(SELECT MAX(productStoreID)
FROM productsStore
GROUP BY productToken)
AND categories.categoryID IN
(SELECT MAX(categoryID)
FROM categories
GROUP BY categoryToken)
ORDER BY categories.categoryID DESC
I would like to retrieve one large table of products with the latest rows from all the joined tables
I think that you want equality conditions with correlated subqueries in the where clause rather than in conditions with aggregate queries. This lets you filter each joined table with the "latest" record for the given productToken.
SELECT *
FROM products p
JOIN productsStore psr ON psr.productToken = p.productToken
JOIN productsStatus psu ON psu.productToken = p.productToken
JOIN productsPrice ppr ON ppr.produstToken = p.productToken
JOIN categories c ON c.categoryToken = p.categoryToken
WHERE
p.shopToken = '$shopToken'
AND p.productID = (SELECT MAX(p1.productID) FROM products p1 WHERE p1.productToken = p.productToken)
AND psr.productStoreID = (SELECT MAX(psr1.productStoreID) FROM productsStore psr1 WHERE psr1.productToken = p.productToken)
AND psu.productStatusID = (SELECT MAX(psu1.productStatusID) FROM productStatus psu1 WHERE psu1.productToken = p.productToken)
AND ppr.productPriceID = (SELECT MAX(ppr1.productPriceID) FROM productsPrice ppr1 WHERE ppr1.productToken = p.productToken)
AND c.categoryID = (SELECT MAX(c1.categoryID) FROM category c1 WHERE c1.productToken = p.productToken)
If you are running MySQL 8.0 (or MariaDB 10.3 or higher), you can use ROW_NUMBER() in subqueries instead:
SELECT *
FROM (
SELECT p.*, ROW_NUMBER() OVER(PARTITION BY productToken ORDER BY productID DESC) rn
FROM products p
) p
INNER JOIN (
SELECT psr.*, ROW_NUMBER() OVER(PARTITION BY productToken ORDER BY productStoreID DESC) rn
FROM productsStore psr
) psr ON psr.productToken = p.productToken AND psr.rn = 1
INNER JOIN (
SELECT psu.*, ROW_NUMBER() OVER(PARTITION BY productToken ORDER BY productStatusID DESC) rn
FROM productsStatus psu
) psu ON psu.productToken = p.productToken AND psu.rn = 1
INNER JOIN (
SELECT ppr.*, ROW_NUMBER() OVER(PARTITION BY productToken ORDER BY productsPriceID DESC) rn
FROM productsPrice ppr
) ppr ON ppr.productToken = p.productToken AND ppr.rn = 1
INNER JOIN (
SELECT c.*, ROW_NUMBER() OVER(PARTITION BY productToken ORDER BY categoryID DESC) rn
FROM categories c
) c ON c.productToken = p.productToken AND c.rn = 1
WHERE p.shopToken = '$shopToken' AND p.rn = 1
Related
select Tf.*
from SalesOrder SO
join TransportOrder Tf on Tf.SalesOrderID = SO.SalesOrderID
join (
select Sz.TradingPartner, Sz.ExternalSalesOrder, Tz.TransportOrderNumber, max(Tz.Revision) Revision
from SalesOrder Sz
join TransportOrder Tz on Sz.SalesOrderID = Tz.SalesOrderID
group by Sz.TradingPartner, Sz.ExternalSalesOrder, Tz.TransportOrderNumber
) TU on TU.TradingPartner = SO.TradingPartner and TU.ExternalSalesOrder = SO.ExternalSalesOrder and TU.TransportOrderNumber = Tf.TransportOrderNumber and Tf.Revision = TU.Revision
I want to know If I can improve it?
What I want to do:
select the TransportOrders that have the maximum revision.
a transport order can be identified with salesOrder.TradingPartner, salesOrder.ExternalSalerOrder, transportOrder.TransportOrderNumer and transportOrder.Revision (used as a version field)
so I want all the transportorder with last version
You can use the ROW_NUMBER analytical function as follows:
SELECT * FROM
(SELECT TF.*,
ROW_NUMBER()
OVER (PARTITION BY SZ.TRADINGPARTNER,
SZ.EXTERNALSALESORDER,
TZ.TRANSPORTORDERNUMBER
ORDER BY TZ.REVISION DESC) AS RN
FROM SALESORDER SO
JOIN TRANSPORTORDER TF
ON TF.SALESORDERID = SO.SALESORDERID
JOIN SALESORDER SZ
ON SZ.TRADINGPARTNER = SO.TRADINGPARTNER
AND SZ.EXTERNALSALESORDER = SO.EXTERNALSALESORDER
JOIN TRANSPORTORDER TZ
ON SZ.SALESORDERID = TZ.SALESORDERID
AND TRANSPORTORDERNUMBER = TF.TRANSPORTORDERNUMBER
)
WHERE TF.REVISION = TU.REVISION
I would suggest window functions
select st.*
from (select t.*, so.TradingPartner, so.ExternalSalerOrder,
max(t.revision) over (partition by so.TradingPartner, so.ExternalSalerOrder, t.TransportOrderNumber) as max_revision
from SalesOrder SO join
TransportOrder t
on t.SalesOrderID = so.SalesOrderID
) st
where revision = max_revision;
No need to reopen the two tables. You can use window functions like this:
select *
from (
select t.*,
rank() over(
partition by s.TradingPartner, s.ExternalSalerOrder, t.TransportOrderNumer
order by t.Revision desc
) rn
from SalesOrder s
join TransportOrder t on t.SalesOrderID = s.SalesOrderID
) t
where rn = 1
I know that you can return only unique rows using distinct operator on a specific column. I successfully use the distinct operator on a column for a query. Now, I would like the query to only return distinct results of the remaining columns. For example the query below:
Select distinct pl.oid, pr.npd, sch.shortstringvalue
from sonpda_rdb.jpipelinesystem pl
join sonpda_rdb.xsystemhierarchy xsys1 on xsys1.oidorigin = pl.oid
join sonpda_rdb.jnameditem it1 on it1.oid = pl.oid
join sonpda_rdb.jrtepiperun pr on pr.oid = xsys1.oiddestination
join sonpda_rdb.jnameditem it2 on it2.oid = pr.oid
join sonpda_rdb.xownsparts xop on xop.oidorigin = pr.oid
join sonpda_rdb.jrtestockpartoccur stckprt on stckprt.oid = xop.oiddestination
join sonpda_rdb.xmadefrom xmf on xmf.oidorigin = stckprt.oid
join sonpda_rdb.jdpipecomponent pipcmp on pipcmp.oid = xmf.oiddestination
join sonpda_rdb.cl_schedulethickness sch on sch.valueid = pipcmp.firstsizeschedule
where it1.itemname = 'C-8001'
order by pr.npd desc;
Gives the results shown in table below
00033457000000000625CE8F235CF10F 2.0 S-40S
000334570000000012BADECCFA5B4804 2.0 S-40S
00033457000000000625CE8F235CF10F 1.0 S-40S
000334570000000012BADECCFA5B4804 1.0 S-40S
000334570000000014BAB9B0FB5B7704 1.0 S-40S
There are only two distinct rows based on the second and third columns of the query. How can I modify the query to only return these two distinct rows?
One method uses row_number():
with q as (
<your query here>
)
select q.*
from (select q.*,
row_number() over (partition by npd, shortstringvalue order by oid desc) as seqnum
from q
) q
where seqnum = 1;
Since Oracle 12C, you can also do this using:
select . . .
from . . .
order by row_number() over (partition by npd, shortstringvalue order by oid desc)
fetch first 1 row with ties;
Please use below query. You have to use row_number().
select
oid, npd, shortstringvalue
from
(Select distinct
pl.oid, pr.npd, sch.shortstringvalue,
row_number() over (partition by pr.npd, sch.shortstringvalue order by sch.shortstringvalue) as rnk
from
sonpda_rdb.jpipelinesystem pl
join
sonpda_rdb.xsystemhierarchy xsys1 on xsys1.oidorigin = pl.oid
join
sonpda_rdb.jnameditem it1 on it1.oid = pl.oid
join
sonpda_rdb.jrtepiperun pr on pr.oid = xsys1.oiddestination
join
sonpda_rdb.jnameditem it2 on it2.oid = pr.oid
join
sonpda_rdb.xownsparts xop on xop.oidorigin = pr.oid
join
sonpda_rdb.jrtestockpartoccur stckprt on stckprt.oid = xop.oiddestination
join
sonpda_rdb.xmadefrom xmf on xmf.oidorigin = stckprt.oid
join
sonpda_rdb.jdpipecomponent pipcmp on pipcmp.oid = xmf.oiddestination
join
sonpda_rdb.cl_schedulethickness sch on sch.valueid = pipcmp.firstsizeschedule
where
it1.itemname = 'C-8001') query
where
rnk = 1
order by
npd desc;
I have the following SQL Server code to get information from a combination of 4 tables.
I would like to modify it to only retrieve the latest 3 orders (pmpOrderDate) by supplier (pmpSupplierOrganizationID).
SELECT
PO.pmpPurchaseOrderID, PO.pmpOrderDate, PO.pmpSupplierOrganizationID, O.cmoName
FROM
PurchaseOrders PO
INNER JOIN
PurchaseOrderLines POL ON PO.pmpPurchaseOrderID = POL.pmlPurchaseOrderID
INNER JOIN
Organizations O ON PO.pmpSupplierOrganizationID = O.cmoOrganizationID
INNER JOIN
Parts P ON POL.pmlPartID = P.impPartID
WHERE
P.impPartClassID LIKE 'PUMP%'
Can you please help?
EDIT:
I wasn't fully clear on my actual requirements. To clarify further, what I need in the end is to display the latest 3 unique Purchase Orders by Supplier ID based on at least one of the PartClassID for the PartID in the PurchaseOrderLines to have criteria of beginning with string 'PUMP'
Use a ROW_NUMBER to partition by pmpSupplierOrganizationID and order by pmpOrderDate.
with cteTopOrders AS (
SELECT PO.pmpPurchaseOrderID, PO.pmpOrderDate, PO.pmpSupplierOrganizationID, O.cmoName,
ROW_NUMBER() OVER(PARTITION BY pmpSupplierOrganizationID ORDER BY pmpOrderDate DESC) AS RowNum
FROM PurchaseOrders PO
Inner Join PurchaseOrderLines POL ON PO.pmpPurchaseOrderID = POL.pmlPurchaseOrderID
Inner Join Organizations O On PO.pmpSupplierOrganizationID = O.cmoOrganizationID
Inner Join Parts P ON POL.pmlPartID = P.impPartID
WHERE P.impPartClassID Like 'PUMP%'
)
SELECT pmpPurchaseOrderID, pmpOrderDate, pmpSupplierOrganizationID, cmoName
FROM cteTopOrders
WHERE RowNum <= 3;
I'm a fan of lateral joins for this . . . cross apply:
select p.*, O.cmoName
from Organizations O cross apply
(select top (3) PO.pmpPurchaseOrderID, PO.pmpOrderDate, PO.pmpSupplierOrganizationID
from PurchaseOrders PO join
PurchaseOrderLines POL
on PO.pmpPurchaseOrderID = POL.pmlPurchaseOrderID join
Parts P
on POL.pmlPartID = P.impPartID
where PO.pmpSupplierOrganizationID = O.cmoOrganizationID and
P.impPartClassID Like 'PUMP%'
order by PO.pmpOrderDate desc
) p
You need a nested row_number to get the three rows per supplier and another OLAP-function on top of it:
with OrderRowNum as
(
SELECT PO.pmpPurchaseOrderID, PO.pmpOrderDate, PO.pmpSupplierOrganizationID, O.cmoName, P.impPartClassID,
row_number()
over (partition by PO.pmpSupplierOrganizationID
order by pmpOrderDate desc) as rn
FROM PurchaseOrders PO
Inner Join PurchaseOrderLines POL ON PO.pmpPurchaseOrderID = POL.pmlPurchaseOrderID
Inner Join Organizations O On PO.pmpSupplierOrganizationID = O.cmoOrganizationID
Inner Join Parts P ON POL.pmlPartID = P.impPartID
)
, CheckPUMP as
(
select *,
-- check if at least one of the three rows contains PUMP
max(case when impPartClassID Like 'PUMP%' then 1 else 0 end)
over (partition by PO.pmpSupplierOrganizationID) as PUMPflag
from OrderRowNum
where rn <= 3 -- get the last three rows per supplier
)
select *
from CheckPUMP
where flag = 1
I need to select reviews for product, but unique by user (i.e. one review from user).
With my code, I select all reviews, and I can see few reviews left by one user.
SELECT
tr.reviewText, tr.reviewDate, tr.reviewRating,
u.userName AS userName,
u.userFirstName AS userFirstName, u.userSurname AS userSurname,
u.countryId AS countryId
FROM
tblReviews tr
INNER JOIN
tblOrderProduct op ON op.orderProductId = tr.orderProductId
AND op.productOptionId IN (SELECT productOptionId
FROM tblProductOption
WHERE productSubCuId = 111
AND productOptionActive = 1)
LEFT JOIN
tblOrder o ON o.orderId = op.orderId
LEFT JOIN
tblUser u ON u.userRandomId = o.userRandomId
WHERE
tr.reviewsStatusId = 2
ORDER BY
tr.reviewRating DESC, tr.reviewDate DESC
OFFSET 0 ROWS FETCH NEXT 100 ROWS ONLY
Can I get just one review from each user?
Maybe I need select userId -> group results by userId and select one per group? [I tried to do so, but I didn't succeed :( ]
You can use row_number to number the reviews and select any one like below:
;with per_user_one_review
as
(SELECT tr.reviewText, tr.reviewDate, tr.reviewRating,
u.userName as userName,
u.userFirstName as userFirstName, u.userSurname as userSurname,
u.countryId as countryId, row_number() over (partition by u.userRandomId order by tr.reviewDate desc) rn
FROM tblReviews tr
INNER JOIN tblOrderProduct op
ON op.orderProductId = tr.orderProductId
AND op.productOptionId IN (
SELECT productOptionId FROM tblProductOption
WHERE productSubCuId = 111 AND productOptionActive = 1
)
LEFT JOIN tblOrder o ON o.orderId = op.orderId
LEFT JOIN tblUser u ON u.userRandomId = o.userRandomId
WHERE tr.reviewsStatusId = 2
ORDER BY tr.reviewRating DESC, tr.reviewDate DESC
OFFSET 0 ROWS FETCH NEXT 100 ROWS ONLY
)
select * from per_user_one_review where rn = 1
It will pick the latest review (reviewDate desc) from the user.
If you need the last review you could use a join with the suquery for max review date grouped by orderProductId
(and as a suggestion you could use a inner join instead of a IN clasue based on a subquery)
select tr.reviewText
, tr.reviewDate
, tr.reviewRating
, u.userName
, u.userFirstName
, u.userSurname
, u.countryId
from tblReviews tr
INNER JOIN (
select max(reviewDate) max_date, orderProductId
from tblReviews
group by orderProductId
) t1 on t1.orderProductId = tr.orderProductId and t1.max_date = tr.reviewDate
INNER JOIN tblOrderProduct op ON op.orderProductId = tr.orderProductId
INNER JOIN (
SELECT productOptionId
FROM tblProductOption
WHERE productSubCuId = 111 AND productOptionActive = 1
) t2 ON op.productOptionId = t2.productOptionId
LEFT JOIN tblOrder o ON o.orderId = op.orderId
LEFT JOIN tblUser u ON u.userRandomId = o.userRandomId
WHERE tr.reviewsStatusId = 2
ORDER BY tr.reviewRating DESC, tr.reviewDate DESC
OFFSET 0 ROWS FETCH NEXT 100 ROWS ONLY
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