SQL Server : get the lowest value - sql-server

Goal : I want to find the lowest NR of DayInStock where the Cummsold > Balance
The query is as follow
SELECT TOP (100) PERCENT
a.MonthNR
, a.DayNR
, a.DayInStock
, a.CummSold
, a.WarehouseID
, a.ItemID
, a.[Group]
, a.Balance
, a.CountryNumber
, a.Country
FROM dbo.VW_Critical_01_01 AS a
JOIN (SELECT MIN(DayInStock) AS DayInStock
, MIN(CummSold) AS Cummsold
, Balance
, ItemID
, [Group]
FROM dbo.VW_Critical_01_01
WHERE CummSold > Balance
GROUP BY DayInStock, CummSold, Balance, ItemID, [Group]
) AS b
ON b.DayInStock = a.DayInStock
AND b.ItemID = a.ItemID
AND b.[Group] = a.[Group]
ORDER BY a.ItemID, a.DayInStock
The query gives my as result:
MonthNR DayNR DayInStock CummSold ItemID Group Balance CountryNumber Country
**2 4 11 2902.492233 100049V3 1 2894 370 Sweden
2 4 11 2902.492233 100049V3 1 2894 280 Norway
2 4 11 2902.492233 100049V3 1 2894 270 Portugal
2 4 11 2902.492233 100049V3 1 2894 460 Finland
2 4 11 2902.492233 100049V3 1 2894 110 Switzerland**
2 5 12 2982.376102 100049V3 1 2894 370 Sweden
2 5 12 2982.376102 100049V3 1 2894 280 Norway
2 5 12 2982.376102 100049V3 1 2894 270 Portugal
2 5 12 2982.376102 100049V3 1 2894 460 Finland
2 5 12 2982.376102 100049V3 1 2894 110 Switzerland
Where I only want to see the values marked as BOLD
As for those the CummSold > Balance (2902 is larger then 2894) and the daynumber is the lowest 11 instead of 12
My SQL Server knowledge seems to stop here. I searched and tried numerous things and perhaps i'm just overlooking something very "stupid"
Any help or suggestions would be appreciated

For SQL Server 2005+ you can try using analytical functions:
;WITH CTE AS
(
SELECT a.MonthNR,
a.DayNR,
a.DayInStock,
a.CummSold,
a.WarehouseID,
a.ItemID,
a.[Group],
a.Balance,
a.CountryNumber,
a.Country,
ROW_NUMBER() OVER(PARTITION BY ItemID, [Group], Country
ORDER BY DayInStock) RN
FROM dbo.VW_Critical_01_01 a
WHERE CummSold > Balance
)
SELECT *
FROM CTE
WHERE RN = 1

something like this?
select DayNR
, DayInStock
, CummSold
, WarehouseID
, ItemID
, [Group]
, Balance
, CountryNumber
, Country
from(SELECT DayInStock
, DayNR
, DayInStock
, CummSold
, WarehouseID
, ItemID
, [Group]
, Balance
, CountryNumber
, Country
, min(DayInStock) over (partition by itemID,Group,Country) as minDayInStock
FROM dbo.VW_Critical_01_01
WHERE CummSold > Balance
)V
where V.DayInStock = V.minDayInStock

Related

How to show order fulfilment in a SQL Server 2008 query

I am trying to think of a way on a SQL Server 2008 database to run through a sales order table and get open demand for a part, order it by due date, then look at a purchase order table and fulfill the sales orders by PO, ordering the PO supply by due date as well. At the same time, I need to show what PO(s) are fulfilling the sales order.
For example:
SO table
SO# DueDate Part Number Required QTY
---------------------------------------------
100 9/3/16 1012 2
101 9/12/16 1012 1
107 10/11/16 1012 4
103 10/17/16 1012 7
PO table:
PO# DueDate Part Number Ordered QTY
--------------------------------------------
331 9/1/16 1012 1
362 9/2/16 1012 1
359 9/24/16 1012 5
371 10/1/16 1012 3
380 10/10/16 1012 10
With this data, I would like to see this result:
SO# DueDate Part Number Required QTY PO number QTY Used QTY Remain
--------------------------------------------------------------------------
100 9/3/16 1012 2 331 1 0
100 9/3/16 1012 1 362 1 0
101 9/12/16 1012 1 359 1 4
107 10/11/16 1012 4 359 4 0
103 10/17/16 1012 7 371 3 0
103 10/17/16 1012 7 380 4 6
I have done this sales order fulfillment process before, but not to the point of breaking down what PO(s) are fulfilling the order, only to the point of summing all open supply, then running through and subtracting the supply from each sales order to get a running balance of supply left.
Many thanks in advance for your help.
I found a bit weird solution, hope it helps you. Maybe later I could optimize it, but now I post it as is:
;WITH cte AS (
SELECT 1 as l
UNION ALL
SELECT l+1
FROM cte
WHERE l <= 1000000
), SO_cte AS (
SELECT *,
ROW_NUMBER() OVER (ORDER BY DueDate ASC) as rn
FROM SO s
CROSS JOIN cte c
WHERE c.l <= s.[Required QTY]
), PO_cte AS (
SELECT *,
ROW_NUMBER() OVER (ORDER BY DueDate ASC) as rn
FROM PO p
CROSS JOIN cte c
WHERE c.l <= p.[Ordered QTY]
), almost_done AS (
SELECT DISTINCT
s.SO#,
s.DueDate,
s.[Part Number],
p.PO#,
s.[Required QTY],
p.[Ordered QTY]
FROM SO_cte s
LEFT JOIN PO_cte p
ON p.rn = s.rn
), final AS (
SELECT *,
ROW_NUMBER() OVER (ORDER BY DueDate) AS RN
FROM almost_done
)
SELECT f.SO#,
f.DueDate,
f.[Part Number],
f.[Required QTY],
f.PO#,
CASE WHEN f.[Ordered QTY]>f.[Required QTY]
THEN ISNULL(ABS(f1.[Required QTY]-f1.[Ordered QTY]),f.[Required QTY])
ELSE f.[Ordered QTY] END
as [QTY Used],
f.[Ordered QTY] -
CASE WHEN f1.PO# = f.PO#
THEN f1.[Ordered QTY]
ELSE
CASE WHEN f.[Ordered QTY]>f.[Required QTY]
THEN ISNULL(ABS(f1.[Required QTY]-f1.[Ordered QTY]),f.[Required QTY])
ELSE f.[Ordered QTY] END
END as [QTY Remain]
FROM final f
LEFT JOIN final f1
ON f.RN = f1.RN+ 1
AND (f.SO# = f1.SO# OR f.PO# = f1.PO#)
OPTION(MAXRECURSION 0)
Output for data you provided:
SO# DueDate Part Number Required QTY PO# QTY Used QTY Remain
100 2016-09-03 1012 2 331 1 0
100 2016-09-03 1012 2 362 1 0
101 2016-09-12 1012 1 359 1 4
107 2016-10-11 1012 4 359 4 0
103 2016-10-17 1012 7 371 3 0
103 2016-10-17 1012 7 380 4 6

SQL, using Group by until specific trend (increment, decrement, same)

I would like to know how can i modify my code for considering all the same values of suppose 10 as UP till the time it is incrementing and then down for decrement and SAME if there is no change till the time there is no variation in the value (increment, decrement, same).
Here is my code :
;with etape1 as
(
select ROW_NUMBER() OVER(ORDER BY mnth) AS id,* from [InsideTSQL2008].[alioune].[Sales]
)
,
etape2 as
(
select
a.id, b.mnth AS START , a.mnth AS FINISH ,
a.qty - b.qty AS TREND
FROM
etape1 a
LEFT JOIN etape1 b
on a.id = b.id+1
)
select * from etape2;
My Result is :
id START FINISH TREND
1 NULL 2007-12-01 NULL
2 2007-12-01 2008-01-01 10
3 2008-01-01 2008-02-01 10
4 2008-02-01 2008-03-01 10
5 2008-03-01 2008-04-01 10
6 2008-04-01 2008-05-01 0
7 2008-05-01 2008-06-01 -10
8 2008-06-01 2008-07-01 -10
9 2008-07-01 2008-08-01 -10
10 2008-08-01 2008-09-01 -10
11 2008-09-01 2008-10-01 10
12 2008-10-01 2008-11-01 -10
13 2008-11-01 2008-12-01 20
14 2008-12-01 2009-01-01 10
15 2009-01-01 2009-02-01 10
16 2009-02-01 2009-03-01 -40
My final result as required should be like :
Start End Trend
200712 200712 unknown
200801 200804 UP
200805 200805 SAME
200806 200809 DOWN
200810 200810 UP
200811 200811 DOWN
200812 200812 UP
200903 200903 DOWN
200904 200905 SAME
200906 200907 UP
Any help would be really helpful; Thanks
Took me a few goes (and a few hours), but I think I have what you want:
DECLARE #Sales AS TABLE (mnth datetime, qty int)
INSERT INTO #Sales
SELECT '2016-01-01', 10 UNION ALL
SELECT '2016-02-01', 20 UNION ALL
SELECT '2016-03-01', 30 UNION ALL
SELECT '2016-04-01', 40 UNION ALL
SELECT '2016-05-01', 40 UNION ALL
SELECT '2016-06-01', 30 UNION ALL
SELECT '2016-07-01', 20 UNION ALL
SELECT '2016-08-01', 30 UNION ALL
SELECT '2016-09-01', 40 UNION ALL
SELECT '2016-10-01', 45 UNION ALL
SELECT '2016-11-01', 50
;WITH etape1 AS (
SELECT ROW_NUMBER() OVER(ORDER BY mnth) AS id, * FROM #Sales
)
, etape2 AS (
SELECT id, lag(mnth) OVER (ORDER BY id) AS START, mnth AS FINISH, CASE WHEN qty - LAG(qty) OVER (ORDER BY id) < 0 THEN -1 WHEN qty - LAG(qty) OVER (ORDER BY id) > 0 THEN 1 ELSE 0 END AS TREND
FROM etape1
)
, etape3 AS (
SELECT id, START, FINISH, TREND, lag(TREND) OVER (ORDER BY id) AS PrevTrend
FROM etape2
)
, etape4 AS (
SELECT id, START, FINISH, TREND, SUM(CASE WHEN TREND = PREVTREND THEN 0 ELSE 1 END) OVER (ORDER BY id ROWS UNBOUNDED PRECEDING) AS Change
FROM etape3
)
SELECT MIN(START) AS START, MAX(FINISH) AS FINISH, CASE WHEN MIN(TREND) IS NULL THEN 'Unknown' WHEN MIN(TREND) < 0 THEN 'Down' WHEN MIN(TREND) > 0 THEN 'Up' WHEN MIN(Start) is NULL THEN 'Unknown' ELSE 'Same' END AS TREND
FROM etape4
GROUP BY Change
ORDER BY START
Results are:
START FINISH TREND
NULL 2016-01-01 Unknown
2016-01-01 2016-04-01 Up
2016-04-01 2016-05-01 Same
2016-05-01 2016-07-01 Down
2016-07-01 2016-11-01 Up

Count field Pivot table In SQL Server

I have this table - Name : Mytable:
Amount Desc Month Sym code ID
$32,323.00 Bla1 1 121 3 2424221
$4,242.00 Bla1 1 121 3 2424221
$3,535.00 Bla1 1 121 1 3230824
$4,984.00 Bla2 1 433 1 3230824
$47,984.00 Bla2 2 433 1 3230824
$41.00 Bla2 2 433 1 3230824
$3,472.00 Bla6 1 D2 27 2297429
$3,472.00 Bla6 1 D2 27 2297429
$3,239.00 Bla6 2 D2 27 2297429
$4,249.00 Bla8 2 114 24 3434334
ID and Month Stands for for a paycheck. There are 6 paychecks : 1 + 3230824, 2+3230824 etc.
And I want to generate a pivot like this:
Jan Feb
count amount count amount
121 2 40100$ 0 0
433 1 52968$ 1 48025$
D2 1 6944$ 1 3239$
114 0 0 1 4249$
Explanation: 121 is two in Jan because ID = 2424221 got it twice and 3230824 got it one time. The number of of "occurrences" in the paychecks is two.
But, In the amount I sum every thing To get the total sum of money in the paycheck for that Sym.
Same, 433 got the value of 1 in Feb for example because only 3230824 got it (twice).
I started writing this:
SELECT *
FROM (
SELECT
[Sym] as Sym, [Month] as [month], [Amount] as Amount
FROM Mytable
) as T
PIVOT
(
Sum(Amount)
FOR [Month] IN ([1],[2])
)AS piv
Well, The amounts are correct But I don't know how can I pull this count as I explained near the amount in the pivot table.
SELECT
[Sym],
COALESCE(SUM(CASE WHEN [1] IS NULL THEN NULL ELSE [Cnt] END), 0) [Jan Count],
COALESCE(SUM(CASE WHEN [1] IS NULL THEN NULL ELSE [1] END), 0) [Jan Amount],
COALESCE(SUM(CASE WHEN [2] IS NULL THEN NULL ELSE [Cnt] END), 0) [Feb Count],
COALESCE(SUM(CASE WHEN [2] IS NULL THEN NULL ELSE [2] END), 0) [Feb Amount]
FROM (
SELECT
mt1.[Sym] as Sym, mt1.[Month] as [month], mt1.[Amount] as Amount, mt2.[Cnt]
FROM Mytable mt1
JOIN (SELECT COUNT(DISTINCT [ID]) [Cnt], [Sym], [Month]
FROM MyTable
GROUP BY [Sym], [Month]) mt2
ON mt1.[Sym] = mt2.[Sym] AND mt1.[Month] = mt2.[Month]
) as T
PIVOT
(
Sum(Amount)
FOR [Month] IN ([1],[2])
)AS piv
GROUP BY [Sym]
SQL Fiddle

Using a CTE to provide a cumulative total

I have a table with some forenames in:
SELECT * FROM d;
Forename
--------------------------------
Robert
Susan
Frances
Kate
May
Alex
Anna
I want to pull a cumulative total of name lengths alphabetically. So far I have:
WITH Names ( RowNum, Forename, ForenameLength )
AS ( SELECT ROW_NUMBER() OVER ( ORDER BY forename ) AS RowNum ,
Forename ,
LEN(forename) AS ForenameLength
FROM d
)
SELECT RowNum ,
Forename ,
ForenameLength ,
ISNULL(ForenameLength + ( SELECT ISNULL(SUM(ForenameLength),0)
FROM Names
WHERE RowNum < n.RowNum
), 0) AS CumLen
FROM NAMES n;
RowNum Forename ForenameLength CumLen
-------------------- -------------------------------- -------------- -----------
1 Alex 4 4
2 Anna 4 8
3 Frances 7 15
4 Kate 4 19
5 May 3 22
6 Robert 6 28
7 Susan 5 33
But I understand that it should be possible to do this (recursively) within the CTE. Anyone know how this could be achieved?
N.B. whilst we are developing on 2012, the current live system is 2008 so any solution would need to be backwards compatible at least in the short term.
You are on SQL Server 2012 and should use sum() over() instead.
select row_number() over(order by d.Forename) as RowNum,
d.Forename,
len(d.Forename) as ForenameLength,
sum(len(d.Forename)) over(order by d.Forename rows unbounded preceding) as CumLen
from d
order by d.Forename;
Result:
RowNum Forename ForenameLength CumLen
-------- ------------ -------------- -----------
1 Alex 4 4
2 Anna 4 8
3 Frances 7 15
4 Kate 4 19
5 May 3 22
6 Robert 6 28
7 Susan 5 33
Update:
If you for some reason absolutely want a recursive version it could look something like this:
with C as
(
select top(1)
1 as RowNum,
d.Forename,
len(d.Forename) as ForenameLength,
len(d.Forename) as CumLen
from d
order by d.Forename
union all
select d.RowNum,
d.Forename,
d.ForenameLength,
d.CumLen
from (
select C.RowNum + 1 as RowNum,
d.Forename,
len(d.Forename) as ForenameLength,
C.CumLen + len(d.Forename) as CumLen,
row_number() over(order by d.ForeName) as rn
from d
inner join C
on C.Forename < d.Forename
) as d
where d.rn = 1
)
select C.RowNum,
C.Forename,
C.ForenameLength,
C.CumLen
from C;
Adapted from Performance Tuning the Whole Query Plan by Paul White.

Rolling up values in SQL Server

This is the result of my first sql statement:
SELECT
count(*) countQuarter, Hour, Quarter,
ROW_NUMBER() OVER(ORDER BY Hour, Quarter ASC) AS rownum
FROM
(SELECT [ID] ,[simulationID] ,[time],
replace(str(time/3600,len(ltrim(time/3600))+abs(sign(time/359999)-1)) + ':' + str((time/60)%60,2) + ':' + str(time%60,2),' ','0') dtString,
(time/3600) Hour, (time/60)%60 Minute, case when (time/60)%60<15 then 15 when
(time/60)%60<30 then 30 when (time/60)%60<45 then 45 when (time/60)%60<60 then 60 end
Quarter ,[person] ,[link] ,[vehicle] FROM [TEST].[dbo].[evtLinks]
WHERE simulationID=#simulationID) B
GROUP BY Hour, Quarter
which gives the following results:
Count Hour Quarter Rownum
497 0 15 1
842 0 30 2
1033 0 45 3
1120 0 60 4
1235 1 15 5
1267 1 30 6
1267 1 45 7
1267 1 60 8
1267 2 15 9
1267 2 30 10
I desire a result, where the column fullCount is the sum of the Count of the actual row and the next 3!
Count Hour Quarter Rownum Fullcount
497 0 15 1 3492
842 0 30 2 4230
1033 0 45 3 4655
1120 0 60 4 ...
1235 1 15 5
1267 1 30 6
1267 1 45 7
1267 1 60 8
1267 2 15 9
1267 2 30 10
How can this be done with grouping or analytical functions in SQL Server?
For SQL Server 2012, yes this can be done:
declare #t table ([Count] int,[Hour] int,[Quarter] int,Rownum int)
insert into #t([Count],[Hour],[Quarter],Rownum) values
(497 , 0 , 15 , 1 ),
(842 , 0 , 30 , 2 ),
(1033 , 0 , 45 , 3 ),
(1120 , 0 , 60 , 4 ),
(1235 , 1 , 15 , 5 ),
(1267 , 1 , 30 , 6 ),
(1267 , 1 , 45 , 7 ),
(1267 , 1 , 60 , 8 ),
(1267 , 2 , 15 , 9 ),
(1267 , 2 , 30 , 10 )
select *,SUM([Count]) OVER (
ORDER BY rownum
ROWS BETWEEN CURRENT ROW AND
3 FOLLOWING)
from #t
Here I'm using #t as your current result set - you may be able to adapt this into your current query or may have to place your current query in a CTE.
Unfortunately, the ROWS BETWEEN syntax is only valid on 2012 and later.
Tested the logical scenario and it works, but I don't have your data, so in your case it should look roughly like this:
;WITH CTE as (SELECT count(*) countQuarter,Hour,Quarter,
ROW_NUMBER() OVER(ORDER BY Hour, Quarter ASC) AS rownum
FROM
(SELECT [ID] ,[simulationID] ,[time],
replace(str(time/3600,len(ltrim(time/3600))+abs(sign(time/359999)-1)) + ':' + str((time/60)%60,2) + ':' + str(time%60,2),' ','0') dtString,
(time/3600) Hour, (time/60)%60 Minute, case when (time/60)%60<15 then 15 when
(time/60)%60<30 then 30 when (time/60)%60<45 then 45 when (time/60)%60<60 then 60 end
Quarter ,[person] ,[link] ,[vehicle] FROM [TEST].[dbo].[evtLinks]
WHERE simulationID=#simulationID) B
GROUP BY Hour, Quarter)
SELECT *, CA.Fullcount
FROM CTE
CROSS APPLY (SELECT SUM(countQuarter) Fullcount FROM CTE C WHERE C.ID BETWEEN CTE.ID AND CTE.ID+3) CA

Resources