How to display only the MAX results from a query - sql-server

I am new to writing MS SQL queries and I am trying to display only the record with the highest field named RecordVersion.
Below is the query that works but displays all records:
SELECT
PriceCalendars.PriceProgramID,
PriceCalendars.EffectiveDateTime,
PriceSchedules.Price,
PriceSchedules.PLU,
items.Descr,
PriceSchedules.LastUpdate,
PriceSchedules.LastUpdatedBy,
PriceSchedules.RecordVersion,
PriceSchedules.PriceScheduleUniqueID
FROM
PriceCalendars
INNER JOIN PriceSchedules ON PriceCalendars.PriceProgramID = PriceSchedules.PriceProgramID
INNER JOIN items ON PriceSchedules.PLU = items.PLU
WHERE
(PriceSchedules.PLU = 'SLS10100103')
AND (PriceCalendars.EffectiveDateTime = '2016-03-22')
Here are the query results:
PriceProgramID EffectiveDateTime Price PLU Descr LastUpdate LastUpdatedBy RecordVersion PriceScheduleUniqueID
1 2016-03-22 00:00:00.000 35.00 SLS10100103 Architecture Adult from NP POS 2015-01-22 07:53:15.000 GX70,83 9 569
1 2016-03-22 00:00:00.000 32.00 SLS10100103 Architecture Adult from NP POS 2014-02-25 16:22:46.000 GX70,83 5 86180
The first line of the results has RecordVersion being 9 and the second line results is 5, I only want the higher record displaying, the one that returned RecordVersion = 9.
Every time I try to use the MAX command I get errors or the group by and I have tried every example I could find on the web but nothing seems to work.
Using MS SQL 2012.
Thanks,
Ken

Try the following query which attempts to solve your problem by ordering the returned rows by RecordVersion DESC and then SELECTs just the first row.
SELECT TOP 1
PriceCalendars.PriceProgramID,
PriceCalendars.EffectiveDateTime,
PriceSchedules.Price,
PriceSchedules.PLU,
items.Descr,
PriceSchedules.LastUpdate,
PriceSchedules.LastUpdatedBy,
PriceSchedules.RecordVersion,
PriceSchedules.PriceScheduleUniqueID
FROM
PriceCalendars
INNER JOIN PriceSchedules ON PriceCalendars.PriceProgramID = PriceSchedules.PriceProgramID
INNER JOIN items ON PriceSchedules.PLU = items.PLU
WHERE
(PriceSchedules.PLU = 'SLS10100103')
AND (PriceCalendars.EffectiveDateTime = '2016-03-22')
ORDER BY
RecordVersion DESC

All group by columns should be in select ,that's the rule of group by.How group by works is for every distinct combination of group by columns,arrange remaining columns into groups,so that any aggregation can be applied,in your case I am not sure what group by columns are unique with out test date.here is one version which use row number which gives you the output desired
Remember ,order by last updated date is the one which decides rows order and assign numbers
WITH CTE
AS
(
SELECT PriceCalendars.PriceProgramID,
PriceCalendars.EffectiveDateTime,
PriceSchedules.Price,
PriceSchedules.PLU,
items.Descr,
PriceSchedules.LastUpdate,
PriceSchedules.LastUpdatedBy,
PriceSchedules.RecordVersion,
PriceSchedules.PriceScheduleUniqueID,
ROW_NUMBER() OVER (PARTITION BY PriceSchedules.RecordVersion ORDER BY PriceSchedules.LastUpdatedBy) AS RN
FROM
PriceCalendars
INNER JOIN PriceSchedules ON PriceCalendars.PriceProgramID = PriceSchedules.PriceProgramID
INNER JOIN items ON PriceSchedules.PLU = items.PLU
WHERE
(PriceSchedules.PLU = 'SLS10100103')
AND (PriceCalendars.EffectiveDateTime = '2016-03-22')
)
SELECT * FROM CTE WHERE RN=1

Related

Optimise query with count and order by function

I have a problem with the optimization of this query, I have 3 tables (Products = Catalogo.GTIN, Sales Header = TEDEF.Factura and Sales Detail = TEDEF.Farmacia).
The query tries to find the Mode of the column VPRODEXENIGV_FAR. This query without the ORDER BY executes in less than 3 seconds (the table of details has about 30 million rows).
But when I add the ORDER BY clause, the query now takes more than 30 minutes to run.
I want to know how can I optimize this query or the indexes that I need to optimize this.
SELECT *
FROM Catalogo.GTIN G
CROSS APPLY
(SELECT TOP 1
COUNT(FAR.VPRODEXENIGV_FAR) [ROW],
YEAR(FAC2.VFECEMI_FAC) [AÑO],
MONTH(FAC2.VFECEMI_FAC) [MES],
FAR.VCODPROD_FAR_003,
CASE WHEN FAR.VPRODEXENIGV_FAR = 'A' THEN 1 ELSE 0 END AfectoIGV
FROM
TEDEF.Factura FAC2
INNER JOIN
TEDEF.Farmacia FAR ON FAC2.VTDOCPAGO_FAC = FAR.VTDOCPAGO_FAC
AND FAC2.VNDOCPAGO_FAC = FAR.VNDOCPAGO_FAC
WHERE
G.CODIGO = FAR.VCODPROD_FAR_003
GROUP BY
YEAR(FAC2.VFECEMI_FAC),
MONTH(FAC2.VFECEMI_FAC),
FAR.VCODPROD_FAR_003,
FAR.VPRODEXENIGV_FAR
ORDER BY
1 DESC --- <----- THE PROBLEM IS HERE
) GG
Ouch! You have a hugely expensive dependent subquery. It's expensive because SELECT TOP(n) ... ORDER BY col DESC does a whole lot of work to create a result set only to discard all but one row. And, it's a dependent subquery so it's run for every row of Catalogo.GTIN .
It looks like you want to count the resultset rows in the most recent month and year for each Catalogo.GTIN row. So, let's try to refactor your query to do that.
We'll start with a subquery to grab the month-start date of the latest Factura row for each catalog entry.
SELECT CODIGO,
DATEFROMPARTS(YEAR(maxd), MONTH(maxd),1) maxmes
FROM (
SELECT MAX(FAC2.VFECEMI_FAC) maxd,
G.CODIGO
FROM Catalogo.GTIN G
JOIN TDEF.Farmacia FAR
ON G.CODIGO = FAR.VCODPROD_FAR_003
JOIN TEDEF.Factura FAC2
ON FAC2.VTDOCPAGO_FAC = FAR.VTDOCPAGO_FAC
AND FAC2.VNDOCPAGO_FAC = FAR.VNDOCPAGO_FAC
GROUP BY G.CODIGO
) maxd
It's wise to test this and make sure it works correctly and performs tolerably well. If you test it in SSMS, you can use "Show Actual Execution Plan" and see if it recommends an extra index. This subquery need only be run once, rather than once per G.CODIGO row.
Then we'll use it in your larger query.
SELECT G.*,
COUNT(FAR.VPRODEXENIGV_FAR) [ROW],
YEAR(FAC2.VFECEMI_FAC) [AÑO],
MONTH(FAC2.VFECEMI_FAC) [MES],
FAR.VCODPROD_FAR_003,
CASE WHEN FAR.VPRODEXENIGV_FAR = 'A' THEN 1 ELSE 0 END AfectoIGV
FROM Catalogo.GTIN G
JOIN (
SELECT CODIGO,
DATEFROMPARTS(YEAR(maxd), MONTH(maxd),1) maxmes
FROM (
SELECT MAX(FAC2.VFECEMI_FAC) maxd,
G.CODIGO
FROM Catalogo.GTIN G
JOIN TDEF.Farmacia FAR
ON G.CODIGO = FAR.VCODPROD_FAR_003
JOIN TEDEF.Factura FAC2
ON FAC2.VTDOCPAGO_FAC = FAR.VTDOCPAGO_FAC
AND FAC2.VNDOCPAGO_FAC = FAR.VNDOCPAGO_FAC
GROUP BY G.CODIGO
) maxd
) maxmes ON G.CODIGO = maxmes.CODIGO
JOIN TEDEF.Farmacia FAR
ON G.CODIGO = FAR.VCODPROD_FAR_003
JOIN TEDEF.Factura FAC2
ON FAC2.VTDOCPAGO_FAC = FAR.VTDOCPAGO_FAC
AND FAC2.VNDOCPAGO_FAC = FAR.VNDOCPAGO_FAC
AND FAC2.VFECEMI_FAC >= maxmes.maxmes
GROUP BY maxmes.maxmes,
G.CODIGO,
FAR.VCODPROD_FAR_003,
FAR.VPRODEXENIGV_FAR
Here is the tricky bit:
DATEFROMPARTS(YEAR(maxd), MONTH(maxd),1) maxmes turns any date maxd into the first day of that month.
And, FAC2.VFECEMI_FAC >= maxmes.maxmes filters out rows before the first day of that month (for that CODIGO). It does so in a sargable way: a way that can exploit an index on FAC2.VFECEMI_FAC.
That is an alternative way to do TOP(1) ORDER BY d DESC. And faster.
It's all about sets of rows. Especially when using GROUP BY, it's performance-helpful to limit the number of rows in each set.
Obviously I cannot debug this.
Is me again, Finally i resolve the problem of the optimization, now the query delay is about 20 sec (with the sort instruction and with the count in a table over 30 million rows) i hope this way can help others or could be optimice more by the community.
I resolve the problem applying the sort but with the Row_Number instruction, in that way the server take my index for the sort instruction and make the magic:
WITH x
AS
(
SELECT *, ROW_NUMBER() OVER (PARTITION BY GG.COD, GG.[AÑO], GG.[MES] ORDER BY GG.[ROW] DESC) [ID]
FROM Catalogo.GTIN G
CROSS APPLY
(
SELECT COUNT(FAR.VPRODEXENIGV_FAR) [ROW]
, YEAR(FAC2.VFECEMI_FAC) [AÑO]
, MONTH(FAC2.VFECEMI_FAC) [MES]
, FAR.VCODPROD_FAR_003 [COD]
, CASE WHEN FAR.VPRODEXENIGV_FAR = 'A' THEN 1 ELSE 0 END AfectoIGV
FROM TEDEF.Factura FAC2
INNER JOIN TEDEF.Farmacia FAR
ON FAC2.VTDOCPAGO_FAC = FAR.VTDOCPAGO_FAC
AND FAC2.VNDOCPAGO_FAC = FAR.VNDOCPAGO_FAC
WHERE G.CODIGO = FAR.VCODPROD_FAR_003
GROUP BY YEAR(FAC2.VFECEMI_FAC)
, MONTH(FAC2.VFECEMI_FAC)
, FAR.VCODPROD_FAR_003
, FAR.VPRODEXENIGV_FAR
-- ORDER BY 1 DESC --- <---- this is the bad guy, please, don't do that xD
) GG
) SELECT *
FROM x WHERE ID = 1
In that way i can sort the Count instruction and calculate the Mode for the Column FAR.VPRODEXENIGV_FAR

How to place subquery in SQL Server 2008

I have a main SQL query which returns stock quantity in dates between and I also need to return the stock as on date along with between dates result.
Main query:
SELECT
TT.TranRId, MAX(TT.TInQty) AS InQty, MAX(TT.TOutQty) AS OutQty
FROM
TReg TR, TTrans TT
WHERE
TR.TRegId = TT.TrRegId
AND TT.Stid = 2
AND TR.TransDate BETWEEN '2018-08-25' AND '2018-08-28'
GROUP BY
TT.TranRId
ORDER BY
TT.TranRId
Sub query:
(SELECT TT.TransRId, (SUM(TT.TInQty) - SUM(TT.TOutQty))
FROM TTrans TT, TReg TR
WHERE TR.TransDate <= '2018-08-24'
AND TR.TRegId = TT.TrRegId
AND TT.Stid = 2 GROUP BY TT.TranRId) --AS Stock
Please help where I should include my sub query in my main query
To get output as follows:
TransRId Stock InQty OutQty
----------------------------------
41 700 1 1000
42 800 5 500
I am not sure I am following your question 100%, if you are just looking to join it as a sub query the below logic should work.
SELECT TT.TranRId
,MAX(TT.TInQty) AS InQty
,MAX(TT.TOutQty) AS OutQty
,Stock.[Sum]
FROM TReg TR
LEFT JOIN TTrans TT
ON TR.TRegId = TT.TrRegId
LEFT JOIN (
SELECT TT.TransRId
,(SUM(TT.TInQty) - SUM(TT.TOutQty)) as Sum
FROM TTrans TT
LEFT JOIN TReg TR
ON TR.TRegId = TT.TrRegId
WHERE TR.TransDate <= '2018-08-24'
AND TT.Stid = 2
GROUP BY TT.TranRId
) AS Stock
ON Stock.TranRId = TT.TranRId
WHERE TT.Stid = 2
AND TR.TransDate BETWEEN '2018-08-25' AND '2018-08-28'
GROUP BY TT.TranRId
ORDER BY TT.TranRId
edit:
I noticed tt.TranRId and tt.Tran***s***RId if this is not a typo it would need to be corrected, if not my answer will not work for you.
If you need specific dates, including the date in the join logic along with the ID would give you the appropriate result...without knowing your data set I am not sure if the TranRId is unique...sorry about that!

Conditional subquery that returns a running total

I am trying to run a subquery with a condition that returns a running total. However, I am receiving the following error:
Only one expression can be specified in the select list when the subquery is not introduced with EXISTS.
Is there any way this code can be salvaged? Please be aware this code is part of a larger script that executes perfectly. The reason I need to keep it in this format is because it is the "missing piece", for lack of a better word.
SELECT A.[WeekEnding],
(
SELECT SUM(A.[Weekly Sales Units]), A.[Description], A.[WeekEnding]
FROM [FACT_SALES_HISTORY] A
INNER JOIN [DIM_DATE] B
ON A.WeekEnding = B.[WeekEnding] WHERE B.[YA Latest 1 Week] = 1
GROUP BY A.[Description], A.[WeekEnding]
) AS 'YA Units'
FROM [FACT_SALES_HISTORY] A
LEFT JOIN [DIM_DATE] B
ON A.WeekEnding = B.[WeekEnding]
The output data, from the code, would look like the following:
[Weekly Sales Units]) A.[Description] A.[WeekEnding]
24 Item One 03-10-2010
55 Item Two 03-10-2010
79 Item One 03-10-2010
98 Item Five 03-10-2010
11 Item Five 03-10-2010
You can't select three different items in your subquery and then use an AS assignment. You could split that into two separate queries and then union them.
SELECT SUM(A.[Weekly Sales Units]), A.[Description], A.[WeekEnding]
FROM [FACT_SALES_HISTORY] A
INNER JOIN [DIM_DATE] B
ON A.WeekEnding = B.[WeekEnding] WHERE B.[YA Latest 1 Week] = 1
GROUP BY A.[Description], A.[WeekEnding]
UNION ALL -- This will only union distinct columns
SELECT A.[WeekEnding]...<Your other columns>
FROM [FACT_SALES_HISTORY] A
t looks like your subquery on its own would provide the sample data and the outer query is trying to sum that up by weekending. If that is the case, then the whole thing could be replaced with this:
SELECT A.[WeekEnding], SUM(A.[Weekly Sales Units]) [YA Units]
FROM [FACT_SALES_HISTORY] A
INNER JOIN [DIM_DATE] B
ON A.WeekEnding = B.[WeekEnding] WHERE B.[YA Latest 1 Week] = 1
GROUP BY A.[WeekEnding]

Counting duplicate items in different order

Goal:
To know if we have purchased duplicate StockCodes or Stock Description more than once on difference purchase orders
So, if we purchase Part ABC on Purchase Order 1 and Purchase Order 2, it should return the result of
PurchaseOrders, Part#, Qty
Purchase Order1, Purchase Order2, ABC, 2
I just don't know how to pull the whole code together, more to the point, how do I know if it's occurred on more than 1 Purchase Order without scrolling through all the results , may also have to do with Multiple (Having Count) Statements as I only seem to be doing by StockCode
SELECT t1.PurchaseOrder,
t1.MStockCode,
Count(t1.MStockCode) AS SCCount,
t1.MStockDes,
Count(t1.MStockDes) AS DescCount
FROM PorMasterDetail t1
INNER JOIN PorMasterHdr t2
ON t1.PurchaseOrder = t2.PurchaseOrder
WHERE Year(t2.OrderEntryDate) = Year(Getdate())
AND Month(t2.OrderEntryDate) = Month(Getdate())
GROUP BY t1.PurchaseOrder,
t1.MStockCode,
t1.MStockDes
HAVING Count(t1.MStockCode) > 1
Using responses I came up with the following
select * from
(
SELECT COUNT(dbo.InvMaster.StockCode) AS Count, dbo.InvMaster.StockCode AS StockCodes,
dbo.PorMasterDetail.PurchaseOrder, dbo.PorMasterHdr.OrderEntryDate
FROM dbo.InvMaster INNER JOIN dbo.PorMasterDetail ON
dbo.InvMaster.StockCode = dbo.PorMasterDetail.MStockCode
INNER JOIN dbo.PorMasterHdr ON dbo.PorMasterDetail.PurchaseOrder = dbo.PorMasterHdr.PurchaseOrder
WHERE YEAR(dbo.PorMasterHdr.OrderEntryDate) = YEAR(GETDATE())
GROUP BY dbo.InvMaster.StockCode, dbo.InvMaster.StockCode,
dbo.PorMasterDetail.PurchaseOrder, dbo.PorMasterHdr.OrderEntryDate
) Count
Where Count.Count > 1
This returns the below , which is starting to be a bit more helpful
In result line 2,3,4 we can see the same stock code (*30044) ordered 3 times on different
purchase orders.
I guess the question is, is it possible to look at If something was ordered more than once within say a 30 day period.
Is this possible?
Count StockCodes PurchaseOrder OrderEntryDate
2 *12.0301.0021 322959 2014-09-08
2 *30044 320559 2014-01-21
8 *30044 321216 2014-03-26
4 *30044 321648 2014-05-08
5 *32317 321216 2014-03-26
4 *4F-130049/TEST 323353 2014-10-22
5 *650-1157/E 322112 2014-06-24
2 *650-1757 321226 2014-03-27
SELECT *
FROM
(
SELECT h.OrderEntryDate, d.*,
COUNT(*) OVER (PARTITION BY d.MStockCode) DupeCount
FROM
PorMasterHdr h
INNER JOIN PorMasterDetail d ON
d.PurchaseOrder = h.PurchaseOrder
WHERE
-- first day of current month
-- http://blog.sqlauthority.com/2007/05/13/sql-server-query-to-find-first-and-last-day-of-current-month/
h.OrderEntryDate >= CONVERT(VARCHAR(25), DATEADD(dd,-(DAY(GETDATE())-1),GETDATE()),101)
) dupes
WHERE
dupes.DupeCount > 1;
This should work if you're only deduping on stock code. I was a little unclear if you wanted to dedupe on both stock code and stock desc, or either stock code or stock desc.
Also I was unclear on your return columns because it almost looks like you're wanting to pivot the columns so that both purchase order numbers appear on the same line.

Count Function with Linked Table

I am attempting to count the number of parts ordered by each of our customers in 2013. However the returned results seem to be grouped by order number and not trader. I am using the following select statement;
SELECT orders.traderid, COUNT(orderitems.partid) AS configuredparts
FROM orders LEFT JOIN orderitems
ON orders.id = orderitems.orderid AND orders.ordertype = orderitems.ordertype
WHERE (orderitems.partid LIKE N'P%') AND (YEAR(orders.createddate) = 2013)
GROUP BY orders.traderid, orderitems.partid, orders.ordertype
HAVING (orders.ordertype = N'SO')
ORDER BY orders.traderid
an example of my results are
traderid configured parts
800001 3
800001 3
800001 2
800001 1
A00002 1
A00002 2
Any help is much appreciated
This answer gives the total number (count) of part ids in table [order items] by trader id in table [orders].
trader_id part_id total_parts
800001 P001 3
800001 P002 2
A00002 P001 1
If table [order items] has a qty column, you should change COUNT(oi.partid) to SUM(oi.qty).
SELECT
o.traderid as trader_id,
oi.partid as part_id,
COUNT(oi.partid) AS total_parts
FROM
orders as o
LEFT JOIN
orderitems as oi
ON
o.id = oi.orderid AND
o.ordertype = oi.ordertype
WHERE
(oi.partid LIKE N'P%') AND
(o.createddate >= '20130101') AND
(o.createddate < '20140101') AND
(o.ordertype = N'SO')
GROUP BY
o.traderid, oi.partid
ORDER BY
o.traderid, oi.partid
Last but not least, why does the caption have a linked table (server)?
If you are using a linked server you will need to use 4 part notation.
Linked_Server_Name.Database_Name.Schema_Name.Object_Name
give this a go
SELECT orders.traderid, COUNT(orderitems.partid) AS configuredparts
FROM orders LEFT JOIN orderitems AND orders.ordertype = orderitems.ordertype
ON orders.id = orderitems.orderid
WHERE (orderitems.partid LIKE N'P%') AND (orders.createddate >= '20130101')
AND (orders.createddate < '20140101') AND (orders.ordertype = N'SO')
GROUP BY orders.traderid
ORDER BY orders.traderid

Resources